Reputation: 2846
I have the following code which encodes an instance of type T
to a String
.
Then tries to convert the encoded string back to an instance of class T
.
package com.ncr.nep.messaging.notifications.tests;
import java.io.IOException;
import java.io.Serializable;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.vertx.core.json.JsonObject;
class T implements Serializable {
private String channel;
//public T() { }
public T(String channel) {
super();
this.channel = channel;
}
public String getChannel() {
return channel;
}
}
public class Test {
public static void main(String[] args) {
T t = new T("abc");
String enc = JsonObject.mapFrom(t).encode();
System.out.println(enc); //prints: {"channel":"abc"}
//now back from String to T
try {
t = new ObjectMapper().readValue(enc,T.class);
System.out.println(t.getChannel());
} catch (IOException e) {
e.printStackTrace();
}
}
}
The readValue method call throws the following exception:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.ncr.nep.messaging.notifications.tests.T: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)
at [Source: {"channel":"abc"}; line: 1, column: 2]
Uncommenting the default constructor fixes the problem and produces the right T
instance.
I find it difficult to conceive that the designers of this utility class, ObjectMapper
, place such a major constraint on their clients.
Note that I could have declared channel to be final, in which case to resolve the issue not only a default constructor needs to be added but also all the members would need to be changed - not to be 'final'...
So my question is this:
What if the designer of class T
specifically prohibits a default constructor. Is there anything else that can be done? is there an annotation that would do the trick?
Upvotes: 1
Views: 325
Reputation: 12440
The JavaBeans pattern requires that:
They are serializable, have a zero-argument constructor, and allow access to properties using getter and setter methods.
Since this form of java classes is often used across many frameworks, the requirement should be expected by users.
The solution of "if the designer of T prohibits default constructor" depends on the specific use case. Most often I'd say that such class is not a bean and therefore is not a good transfer object - you'd better use your own transfer object that adheres to the expected format and provides methods to convert it from/to the target class.
Upvotes: 0
Reputation: 1706
The problem is weather MOXy or Jackson both need a way to create an object. You only provide T.class
. How should they know how to use your constructor. In your case it may be simple, but for
public T(String a, String b) {..}
it will be more difficult. In this case you could add another constraint like paramater name need to match json attribute name. I guess this would be the same drawback as with a default contructor.
Update: I didn't know of the solution @Link64 described, but if this is better. I don't know. MOXy provides a XMLAdapter to create an object. If for example class T is not under your control.
Upvotes: 1
Reputation: 770
You can try to annotate the constructor with @JsonCreator
and the parameters with @JsonProperty
like this
@JsonCreator
public T(@JsonProperty("channel") String channel) {
super();
this.channel = channel;
}
Upvotes: 3