Scala constructors using val not playing nicely with serialization framework - scala

I'm having an issue with some Scala code and am trying to rule out a bad class design (well, constructor design) before I begin to treat it as a networking issue.
So I have a model Scala class called Hail:
class Hail(val handle : String, val message : String) extends BaseMessage {
def this() {
this("default_user", "default_message")
}
}
abstract class BaseMessage extends AbstractMessage(true) {
}
// This is a 3rd party open source class written in Java
public abstract class AbstractMessage implements Message
{
private transient boolean reliable = true;
protected AbstractMessage()
{
}
protected AbstractMessage( boolean reliable )
{
this.reliable = reliable;
}
public Message setReliable(boolean f)
{
this.reliable = f;
return this;
}
public boolean isReliable()
{
return reliable;
}
}
// This is also a 3rd party open source class written in Java
public interface Message
{
public Message setReliable(boolean f);
public boolean isReliable();
}
At runtime, instances of this class get serialized (to binary), sent over the wire to a server, where they are deserialized (back into Hail instances) and processed.
So I have client code that looks like this:
val h1 : Hail = new Hail("user1", "Hello!")
val h2 : Hail = new Hail("user2", "Aloha!")
val h3 : Hail = new Hail("user3", "Bien venu mes amigos")
client.send(h1)
client.send(h2)
client.send(h3)
When the server receives these messages, it prints out their handle/message combos to STDOUT. The messages I receive are as follows:
Server received a Hail: default_user, default_message
Server received a Hail: default_user, default_message
Server received a Hail: default_user, default_message
Instead of what I would be expecting:
Server received a Hail: user1, Hello!
Server received a Hail: user1, Aloha!
Server received a Hail: user3, Bien venu mes amigos
Again, this could be a networking/serialization/server-side issue. But before I go down that route I want to make sure my Hail class has been written correctly.
The serialization framework I'm using requires all messages (such as Hail) to have no-arg constructors (hence the one I provided above). So it seems to me that something is wrong with my other constructor, and perhaps the server defaults to calling the no-arg constructor because it can't use anything else.
I decompiled my Hail class and see the following:
#ScalaSignature(bytes="<lots of bytes here omitted for brevity")
public class Hail
extends BaseMessage
{
private final String handle;
public String handle()
{
return this.handle;
}
public String message()
{
return this.message;
}
public Hail()
{
this("default_user", "default_message");
}
public Hail(String handle, String message) {}
}
Right away several things are curious/suspicious to me:
Although I see a private final String handle (which is desired!), I don't see a reciprocal private final String message field...
Also, the 2nd constructor (public Hail(String handle, String message)) is empty/undefined. This is probably the root of my issues.
So I ask, how can I refactor Hail's source so that the following end result is bytecode that would decompile to:
#ScalaSignature(bytes="<lots of bytes here omitted for brevity")
public class Hail
extends BaseMessage
{
private final String handle;
public String handle()
{
return this.handle;
}
public String message()
{
return this.message;
}
public Hail()
{
this("default_user", "default_message");
}
public Hail(String handle, String message)
{
this.handle = handle;
this.message = message;
}
}
Any ideas?

The problem is that the serializer server-side uses the no-arg constructor, and then change the values of mutable parameters in the class.
However, scala vals are not mutable, so they are compiled as final parameters of your class, and as such cannot be mutated. So the objects are instantiated with the default values, and then keep those values, since they cannot be mutated.
I would recommend using a scala-compatible serializer, but a simpler solution is to allow the properties to be mutated by declaring them as vars instead of vals.

Related

(quarkus-kafka) Deserialize complex object with nested complex objects in consumerRecord?

In a quarkus application, We have a complex object with other complex objects as attributes and we need to deserialize this from a consumerRecord. here are the classes examples
'''
#Data
public class Person {
private Hobbies hobbies;
private List<Relatives> relatives;
}
#Data
public class Hobbies {
private Sports sports;
private String principal;
}
#Data
public class Parents {
private Children kids;
private String mom;
}
'''
We have a consumer to receive the message like this
'''
#Incoming("topic_test")
public void process(ConsumerRecord<String, Person> consumerRecord {
log.info("Message key[{}] body [{}], consumerRecord.key(), consumerRecord.value());
final var person = toPerson(consumerRecord::value);
//call service
...
}
private Person toPerson(Callable<Person> callable) {
try{
return callable.call();
} catch Exception(e) {
return null;
}
}
'''
and finally we got our properties file
'''
%prod.mp.messaging.incoming.topic_test.connector=smallrye-kafka
%prod.mp.messaging.incoming.topic_test.topic=test-topic
%prod.mp.messaging.incoming.topic_test.value.serializer=io.quarkus.kafka.client.serialization.ObjectMapperSerializer
%prod.mp.messaging.incoming.topic_test.value.deserializer=org.apache.kafka.common.serialization.StringDeserializer
'''
I´m not sure about those deserializer configuration if it´s correct for our scneario, but also I didn´t find any way to deserialize this object 'Person'. We´ve tried to change for ObjectMapperSerializer but got same exception every time. Also tried to change consumeRecord for byte[] and String but it didn´t worked too, when we tried to call readValue using object mapper it couldn´t deserialize the object correctly.
'''
A message sent to channel 'topic_test' has been nacked, fail-stop
A failure has been reported for Kafka topics [test-topic]:
com.faster.jackson.databind.exc.InvalidDefinitionException: Cannot construct instace of 'projectpath'.Person (no Creators, like default constructor, exist): Cannot deserialize from Object value (no delegate- or property-based Creator)
'''
Also, I noticed that now messages are no longer consumed and are stuck on the partition
Can someone help me?

Could you explain me one OOP confusion?

I am creating a program for testing a website. Site has a registration process, which I am testing.
I have created a class named "Client", which should store the information about the client (name, family name, e-mail etc.).
Since I am testing, I use random number generator to generate a name for the client (I have the list of names, one of which is chosen randomly).
Obviously, I should create a method "generateName ()".
But the question is: in which class I should create it?
Lots of programmers would create the method in the Client class. And would do something like that:
client = new Client ();
client.generateName ();
But I have read, that this approach is incorrect - because the client does not generate name for himself. Program does.
Based on that information, I do as follows:
class Program
{
private void generateName ();
}
...
class Client
{
...
public void name ( String name )
{
this.name = name;
}
}
program = new Program ();
program.launch();
client = new Client ();
client.name ( program.generateName () );
But as I know, this approach is not used by the developers.
Could you clarify, how to know "what is right and what is wrong" here? And what information source should I use as an arbitrary for the cases of this kind?
It sounds like generateName() could be a static method in Client, since it's independent of instances:
class Client {
private String name;
public Client(String name) {
this.name = name;
}
public static String generateRandomName() {
String generatedName = ...;
return generatedName;
}
}
You could the simply pass it's value to the Client object as you currently are, or via the constructor:
client = new Client(Client.generateRandomName());
Otherwise, I'd suggest a ClientNameGenerator to handle name generation, to keep inline with SRP and to raise cohesion. This would be the better choice, seeing how you may be needing more name generation methods in the future:
class ClientNameGenerator {
public String generateRandomName() {
String generatedName = ...;
return generatedName;
}
//other name generation methods...
}
You can now use a ClientNameGenerator object to manage the generation of client names:
ClientNameGenerator nameGenerator = new ClientNameGenerator();
client = new Client(nameGenerator.generateRandomName());
Anytime you need to generate a name, simply use the ClientNameGenerator object you created.
There are a number of places which might be appropriate locations for this functionality.
You could have it as a private method on the Client class, used by a static factory method for generating Clients with a random name.
public class Client {
....
public static Client randomlyNamed() {
return new Client(randomName());
}
private static String randomName() {
return ...;
}
}
But that private method might be better extracted to a more appropriate class for generating random Strings...
public class Client {
private static final int defaultNameLength = 8;
....
public static Client randomlyNamed() {
return new Client(Strings.randomString(defaultNameLength));
}
}
public class Strings
private static String randomString(int length) {
return ...;
}
}
You could then expand the static method into a general purpose ClientBuilder class, with an instance method named something like 'withRandomName()'.
public class Client {
...
}
public class ClientBuilder {
private static final int defaultNameLength = 8;
...
public ClientBuilder randomlyNamed() {
this.name = Strings.randomString(defaultNameLength);
}
public Client build() {
return new Client(name);
}
}
public class Strings
private static String randomString(int length) {
return ...;
}
}
An alternative would be an implementation of a NamingStrategy (e.g. ``) object which is given to a ClientBuilder object.
public class RandomNames implements NamingStrategy {
private static final int defaultNameLength = 8;
public String name() {
return String.randomString(defaultNameLength);
}
}
public class ClientBuilder {
private final NamingStrategy nameSource;
public ClientBuilder(NamingStrategy nameSource) {
this.nameSource = nameSource;
}
public Client build() {
return new Client(nameSource.name());
}
}
The pure way to go would be to have a separate class ClientGenerator that produces clients. Because generating clients is not typical client behavior and in your application model a client is no more than a passive data container for client properties. However, generating clients is an activity in "the client domain". Therefor it would be defendable to create a static method Client.NewClient(), like the .NET feamework does with Guid. On the other hand, a guid's very nature is to be generated, it does not represent something in the real world. It IS a spawnable id. So the comparison may not be all that ligitimate.
A common similar mistake (or impurity if you wish) is a Save method on an object. Instead one should have a Persister class that does the job. Or a Manager. Because Save is something you can do to or with the class, not behavior of the class ifself.

Morphia converter calling other converters

I want to convert Optional<BigDecimal> in morphia. I created BigDecimalConverter, and it works fine. Now I want to create OptionalConverter.
Optional can hold any object type. In my OptionalConverter.encode method I can extract underlying object, and I'd like to pass it to default mongo conversion. So that if there is string, I'll just get string, if there is one of my entities, I'll get encoded entity. How can I do it?
There are two questions:
1. How to call other converters?
2. How to create a converter for a generic class whose type parameters are not statically known?
The first one is possible by creating the MappingMongoConveter and the custom converter together:
#Configuration
public class CustomConfig extends AbstractMongoConfiguration {
#Override
protected String getDatabaseName() {
// ...
}
#Override
#Bean
public Mongo mongo() throws Exception {
// ...
}
#Override
#Bean
public MappingMongoConverter mappingMongoConverter() throws Exception {
MappingMongoConverter mmc = new MappingMongoConverter(
mongoDbFactory(), mongoMappingContext());
mmc.setCustomConversions(new CustomConversions(CustomConverters
.create(mmc)));
return mmc;
}
}
public class FooConverter implements Converter<Foo, DBObject> {
private MappingMongoConverter mmc;
public FooConverter(MappingMongoConverter mmc) {
this.mmc = mmc;
}
public DBObject convert(Foo foo) {
// ...
}
}
public class CustomConverters {
public static List<?> create(MappingMongoConverter mmc) {
List<?> list = new ArrayList<>();
list.add(new FooConverter(mmc));
return list;
}
}
The second one is much more difficult due to type erasure. I've tried to create a converter for Scala's Map but haven't found a way. Unable to get the exact type information for the source Map when writing, or for the target Map when reading.
For very simple cases, e.g. if you don't need to handle all possible parameter types, and there is no ambiguity while reading, it may be possible though.

Deserialization of ArrayList GWT

In my application I'm getting some data from a file located in the server. The data is stored in a text file (.obj), so I'm using an rpc to read the file and get the data. The file is read using a third party library http://www.pixelnerve.com/processing/libraries/objimport/ I'm sending the data to the client using ArrayLists, basicly I'm sending this: ArrayList[ArrayList[Vertex3dDTO]] where Vertex3dDTO is an serializable object with contains float parameters. ArrayList[Vertex3dDTO] is contained in another serializable class Face3dDTO, and ArrayList[Face3dDTO] is in the serializable class Group3dDTO.
package com.nyquicksale.tailorapp.shared;
import java.io.Serializable;
public class Vertex3dDTO implements Serializable {
float x,y,z;
public Vertex3dDTO(){
}
public Vertex3dDTO(float x, float y, float z){
this.x = x;
this.y = y;
this.z = z;
}
}
public class Face3dDTO implements Serializable {
ArrayList<Vertex3dDTO> vL = new ArrayList<Vertex3dDTO>();
Vertex3dDTO normal = new Vertex3dDTO();
Vertex3dDTO color = new Vertex3dDTO();
public Face3dDTO(){
}
public Face3dDTO(ArrayList<Vertex3dDTO> v) {
for(Vertex3dDTO v3dDTO : v){
vL.add(v3dDTO);
}
updateNormal();
}
public class Group3dDTO implements Serializable {
ArrayList<Face3dDTO> fL = new ArrayList<Face3dDTO>();
String name;
public Group3dDTO(){
}
public Group3dDTO(ArrayList<Face3dDTO> f) {
for(Face3dDTO f3dDTO : f){
fL.add(f3dDTO);
}
}
}
Now, everything is working well in development mode, but when I tested the application in hosted mode, everything I receive as response is: //OK[0,1, ["java.util.ArrayList/4159755760"],0,7]
So, I've been checked some other questions and seems the problem is about deserialization, but I've not found anything concrete.
The question is what do I have to do to get the app working well in hosted mode?
To successfully use RPC, your object needs to implement Serializable and should also have a default no arg constructor
Have you made sure this is a serialization problem? You can write a simple RPC test method to pass an array list of your DTO's over the wire in hosted mode.
If I were to bet money on a guess, I would say the problem is those array lists are sent empty in hosted mode. The .obj file read could be the problem. Perhaps in hosted mode the path of file doesn't match as in dev mode(different server configurations perhaps?), since file operations are in a try catch block an exception is most likely swallowed.
Long word short, Did you make sure those array lists are not sent empty in hosted mode?
Your object may well be Serializable, but that doesn't equate to something usable by Remote Procedure Calls. You need to implement Serializable, have a default contructor with no arguments (that calls super() if necessary), and a serial version ID, like so:
public class MyObject implements Serializable {
/**
*
*/
private static final long serialVersionUID = -1796729355279100558L;
private Float someValue;
public MyObject() {
super();
}
public MyObject(Float someValue) {
super();
this.someValue = someValue;
}
public Float getSomeValue() {
return someValue;
}
public void setSomeValue(Float someValue) {
this.someValue = someValue;
}
}

Sending a ValueProxy for an immutable class upstream to server

Suppose I am trying to use GWT's RequestFactory to pass an immutable type between client and server, bidirectionally. Let's say the underlying type is TimeOfDay, which is designed to be immutable:
public class TimeOfDay {
private final int hours;
private final int minutes;
public TimeOfDay(final int hours, final int minutes) {...}
public int getHours() {...}
public int getMinutes() {...}
}
I can proxy this class with a ValueProxy:
#ProxyFor(TimeOfDay.class)
public interface TimeOfDayProxy extends ValueProxy {
public int getHours();
public int getMinutes();
}
Now, I can quite easily create TimeOfDay instances on the server side and return them to the client, via this on server side:
public class TimeOfDayService {
public static TimeOfDay fetchCurrentTofD() {
return new TimeOfDay(16, 20);
}
}
...and this on the client side:
#Service(TimeOfDayService.class)
public interface TimeOfDayRequestContext extends RequestContext {
Request<TimeOfDayProxy> fetchCurrentTofD();
}
...
final Receiver<TimeOfDayProxy> receiver = new Receiver<TimeOfDayProxy>() {...};
final TimeOfDayRequestContext context = myFactory.timeOfDayRequestContext();
final Request<TimeOfDayProxy> fetcher = context.fetchCurrentTofD();
fetcher.fire(receiver);
...
This works great. But, if I try this in the reverse direction I hit snags. I.e., on server side:
public class TimeOfDayService {
public static void setCurrentTofD(final TimeOfDay tofd) {...}
}
...and on client side:
#Service(TimeOfDayService.class)
public interface TimeOfDayRequestContext extends RequestContext {
Request<Void> setCurrentTofD(TimeOfDayProxy tofd);
}
...
final Receiver<Void> receiver = new Receiver<Void>() {...};
final TimeOfDayRequestContext context = myFactory.timeOfDayRequestContext();
final TimeOfDayProxy tofdProxy = GWT.create(TimeOfDayProxy.class);
<???>
final Request<Void> setter = context.setCurrentTofD(tofdProxy);
setter.fire(receiver);
...
Snag #1 is that I have no way to set the (immutable) contents of tofdProxy, since GWT.create() just makes a default constructed proxy (i.e. what goes in place of "???"?). Snag #2 is the "No setter" error on the server side.
Is there some magic to circumvent these snags? AutoBeanFactory.create() has a two-argument variant which takes an object to be wrapped by an autobean --- something like that would take care of Snag #1 (if such a thing existed for create() of ValueProxys). As for Snag #2, well, I'm sure there are many clever approaches to deal with the issue; the question is, have any been implemented yet in GWT?
RequestFactory requires default-instantiable classes with setters for client-to-server communications.
There's a pending request for enhancement to add support for immutable classes, using a builder pattern: http://code.google.com/p/google-web-toolkit/issues/detail?id=5604