Kryo serialization refuses to register class - scala

I'm trying to use kryo serialization with:
kryo.setRegistrationRequired(true);
I keep getting the following error saying that a certain class is not registered:
java.lang.IllegalArgumentException: Class is not registered: com.my.package.MyClass[]
Note: To register this class use: kryo.register(com.my.package.MyClass[].class);
However, I do register it:
kryo.register(classOf[MyClass[_]])
When I set Log.TRACE() I get the following output:
00:11 TRACE: [kryo] Register class ID 51: com.my.package.MyClass (com.esotericsoftware.kryo.serializers.FieldSerializer)
Why does it say it is not registered, when the trace logger prints that it has been registered. I cannot find any useful documentation on the matter. Has anyone experienced this before? If it helps i'm running Apache Spark v0.8.1

I figured out what the issue was. I was mistaking the java array syntax [] for the scala generic syntax []. The exception was being being thrown since I did not register an array of MyClass.
So in java
kryo.register( MyClass[].class );
And scala
kryo.register( classOf[ Array[ MyClass[_] ] ] )

Related

How to configure object mapping for MongoDB with Micronaut and Kotlin + KMongo?

I'm having some difficulty configuring object mapping for MongoDB in Micronaut with Kotlin. I'm getting errors like:
Decoding into a 'Asset' failed with the following exception:
Cannot find a public constructor for 'Asset'.
A custom Codec or PojoCodec may need to be explicitly configured and registered to handle this type.
org.bson.codecs.configuration.CodecConfigurationException: An exception occurred when decoding using the AutomaticPojoCodec.
Decoding into a 'Asset' failed with the following exception:
Cannot find a public constructor for 'Asset'.
A custom Codec or PojoCodec may need to be explicitly configured and registered to handle this type.
With KMongo, this is easy. However the MongoClient injected by Micronaut doesn't have KMongo's codec registry.
I can get it working as follows:
val db: MongoDatabase by lazy {
val codecRegistry = ClassMappingType.codecRegistry(MongoClientSettings.getDefaultCodecRegistry())
client.getDatabase("db-name").withCodecRegistry(codecRegistry)
}
This code is taken directly from KMongo. (BTW, using database.withKMongo() resulted in the same error)
Although this works, what I'd like is to let Micronaut use KMongo to create the client, or let it use its codec like above, using configuration (application.yml).
There is a codec-registry setting mentioned here: https://micronaut-projects.github.io/micronaut-mongodb/latest/guide/configurationreference.html, but I have no idea what to enter in that setting to make it work.
Any help is appreciated!
You can simply define the codec registry as a bean. Since you aren't in control of the class being registered you can create a factory
#Factory
class KMongoFactory {
#Singleton
fun kCodecRegistry(): CodecRegistry {
return ClassMappingType.codecRegistry(MongoClientSettings.getDefaultCodecRegistry());
}
}
Something like the above should do it
EDIT: Be aware that MongoClients.getDefaultCodecRegistry() is added by default

EclipseLink-Moxy Unable to load custom DomHandler class while instantiating JAXB context

I am using Eclipselink Moxy Implementation of JAXB in my project to map complex XML to String Object using XmlAnyElement.
For this I have implemented DomHandler named as LayoutHandler.
I am using JAXB for resteasy web services deployed in JBoss 6.
I am facing Below issue intermittently -
Exception [EclipseLink-50033] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b):
org.eclipse.persistence.exceptions.JAXBException
Exception Description: The DomHandlerConverter for DomHandler
[com.**.LayoutHandler] set on property [layoutXml] could not be
initialized.
Internal Exception: java.lang.ClassNotFoundException:
com.**.LayoutHandler from
BaseClassLoader#5c0b3ad0{vfs:///*/*/jboss-server/server/all/deployers/resteasy.deployer}
While EclipseLink Moxy is instantiating JAXBContext using JAXBContext.newInstance(classes, properties)
After spending some time in debugging and analyzing the issue I could figure out that ClassLoader of resteasy is getting used to load LayoutHandler class instead of my application class loader(vfs://///jboss-server/server/all/deploy/app_name.ear/app_name.war/) which is causing the issue as its unable to find the LayoutHandler class.
When I bounce the server, issue is getting resolved so I am unable to find out the exact root cause. Any help will be appreciated.
Further debugging into org.eclipse.persistence.jaxb.JAXBContextFactory revealed that below two classes are getting passed to createContext() method of JAXBContextFactory -
org.jboss.resteasy.plugins.providers.jaxb.JaxbCollection
com.**.Model_class
public static javax.xml.bind.JAXBContext createContext(Class[] classesToBeBound, Map properties) throws JAXBException {
ClassLoader loader = null;
if (classesToBeBound.length > 0) {
loader = classesToBeBound[0].getClassLoader();
}
return createContext(classesToBeBound, properties, loader);
}
In above method classloader of first class is getting used to load the custom DomHandler later on.
When first element in array is model class at that time code is working fine as application context class loader is getting used but when the first element in array is JaxbCollection rest easy context class loader is getting used and its throwing mentioned exception.
This issue is occurring intermittently as order of elements in array is varying which might be due to the use of HashSet to hold the elements of type Class by caller of this method which is passing the classesToBeBound array
Note: I have replaced actual package names with *.
I'm surprised it works on a bounce... all of your JAXB bits need to line up, you should be using the moxy jaxb provider at all times. If it's failing after initial deploy, then working after a bounce, I suspect that you want to specify the moxy jaxb provider in your system properties ( -Djavax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory ) and ensure that they're available to jboss when your app is not deployed.

Why is Ficus throwing an exception when I try to add a new field in my case class?

My application parses settings using "typesafe.config" and then converts the Config object into an instance of a case class using "ficus". The case class currently has 19 constructor arguments. And everything works normally. However, when I add a new argument and a new corresponding field in my "settings.conf", I get the following exception:
An exception or error caused a run to abort: MyCaseClass.<init>(Ljava/lang/String;Lscala/Option;Lscala/Option;IZLscala/collection/Seq;Ljava/lang/String;ILscala/concurrent/duration/FiniteDuration;ZLscala/Option;Lscala/Option;ILscala/Option;Lscala/concurrent/duration/FiniteDuration;Ljava/lang/String;Ljava/lang/String;II)V
java.lang.NoSuchMethodError: MyCaseClass.<init>(Ljava/lang/String;Lscala/Option;Lscala/Option;IZLscala/collection/Seq;Ljava/lang/String;ILscala/concurrent/duration/FiniteDuration;ZLscala/Option;Lscala/Option;ILscala/Option;Lscala/concurrent/duration/FiniteDuration;Ljava/lang/String;Ljava/lang/String;II)V
I can see the "typesafe.config" is correctly parsing my new field into the Config object. But ficus then throws this exception. The new field and the new case class constructor argument have exactly the same name, as they should.
Any ideas why this may be happening?
The concrete problem is documented in the following commits:
1) https://github.com/ceilican/Scorex/commit/133157a6ad070cad7a57624c511ee917133ed5f1
2) https://github.com/ceilican/Scorex/commit/074e0bc5add3c666b0943497a5579f3fd365084d
3) https://github.com/ceilican/Scorex/commit/7c8d3475377a17b2a5383bf3a99d797650ca8bc3
The first two commits are working. With the third one, the exception mentioned above is thrown.
As you can see, there is not much conceptual difference between commits 2 and 3. I don't understand why commit 2 works, whereas commit 3 doesn't.
For a moment I thought it could be because of the large number of arguments in the case class, but the following commit shows that the problem also happens when I add the new field to a smaller case class:
4) https://github.com/ceilican/Scorex/commit/1c253b2b526db1539fa674069232cf02784c4bfb
The same kind of exception is thrown when I try to run the code after commit 4.
Is this a bug in Ficus?
After doing sbt clean on the main project and on subprojects, the problem stopped happening. My guess is that Ficus's macro magic generates functions based on my case classes, but they are not re-generated when the case classes are modified. Then, when Ficus tries to use the outdated functions that are incompatible with the new case classes, the exception is thrown.
Interestingly, the lack of re-generation happens only when I modify "nested" case classes. If the config file is:
main {
nested {
param: 0
}
}
with case classes:
case class MainCaseClass(nested: NestedCaseClass)
case class NestedCaseClass(param: Int)
Then, modifying MainCaseClass does not cause problems, but modifying NestedCaseClass does.

Getting a weird cast exception : javax.mail.session cannot be cast to javax.mail.session

I am trying to use apche-commons-email API for sending an email, in my java web application. I have configured the jboss5 mail-service.xml to send emails from Gmail id. But I am getting the error
org.jboss.resteasy.spi.UnhandledException: java.lang.ClassCastException:
javax.mail.Session cannot be cast to javax.mail.Session
when executing the line
Session mailSession = (Session) ictx.lookup("java:/Mail");
Please help.
I can only see this as a custom class loader loading a javax.mail.Session class along with the original javax.mail.Session object !
But when attempting to cast an object of the first class to an instance of the second, an exception occurs because both objects don't match (i.e. method names, member variables..etc)
Check this answer and other answers for the same question.

Persisting Classes implementing an interface with GORM MongoDB Plugin

I am having a problem while persisting a class. I have a class called Scraper which uses an interface called Paginator. There are several implementations of the Paginator interface which will be instantiated at runtime. So the structure looks like this:
class Scraper {
//some code
Paginator paginator
//more code
def Scraper(Paginator paginator){
this.paginator = paginator
}
}
and then there are the concrete implementations of the paginator interface lets say paginatorA and paginatorB. So now I am trying to do the following:
PaginatorA p = new PaginatorA()
Scraper s = new Scaper(p)
s.save(flush:true)
...and what it get is:
Error Error executing script TestApp:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongoDatastore': Cannot resolve reference to bean 'mongoMappingContext' while setting bean property 'mappingContext';
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongoMappingContext': FactoryBean threw exception on object creation; nested exception is java.lang.NullPointerException (Use --stacktrace to see the full trace)
Can anybody tell me what to make of this? I guess it has something to do with the Mapper because it doesn't know which concrete Paginator to use or how to persist it? If that is the case then how can I tell the framework what to do? I tried to come up with a solution for hours now and am really frustrated so any help would be really really appreciated.
Oh btw I also tried implementing against the concrete implementation (PaginatorA) ... this works perfectly fine since my assumption that it has something to do with the paginator interface.
Thanks for any response...
The error is bad, you should probably raise a JIRA issue for that, but fundamentally there are 2 problems I can see with the code:
Your persistent classes must have a public no-args constructor as per any JavaBean, by adding a constructor that takes your interface, you are no longer providing one
Your Scraper class needs to mark the 'Paginator' as transient to tell the persistence engine not to attempt to persist the 'paginator' property. Since this a custom interface it will not know how to persist it.