Reputation: 49
Let's say my POJO is limited to the following:
public class TestPojo {
StringProperty myField;
public TestPojo(){}
public TestPojo(String myField) {
this.myField = new SimpleStringProperty(myField);
}
public String getMyField() {
return this.myField.get();
}
public StringProperty myFieldProperty() {
return this.myField;
}
public void setMyField(String myField) {
this.myField.set(myField);
}
}
I want to deserialize with Jackson. Jackson doesn't seem to like StringProperty, because as a normal String it works as expected. So I write a custom deserializer...
public class StringPropertyDeserializer extends JsonDeserializer<StringProperty> {
public StringPropertyDeserializer() {}
@Override
public StringProperty deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
throws IOException, JsonProcessingException {
String value = jsonParser.readValueAs(String.class);
return new SimpleStringProperty(value);
}
}
And I add this annotation to my StringProperty field...
@JsonDeserialize(using = StringPropertyDeserializer.class)
I get the following error:
com.fasterxml.jackson.databind.JsonMappingException: Class com.test.example.TestPojo$StringPropertyDeserializer has no default (no arg) constructor
I added a default constructor into the deserializer (as you can see above) and I get the same error regardless of it being there. Any solutions? This seems like it should be simple.
Edit here is the actual code where I'm making the call if that's helpful...
@GET("/api/test")
Call<List<TestPojo>> testPojoCall();
And it's configured in Gradle like so:
compile group: 'com.squareup.retrofit2', name: 'converter-jackson', version: '2.1.0'
That is everything related to this code.
Upvotes: 1
Views: 1879
Reputation: 209438
Your POJO implementation isn't correct: the no-arg constructor doesn't initialize the StringProperty
. Consequently, if you use the no-arg constructor, then call setMyField(...)
you'd get a null pointer exception. I'm guessing that trying to work around that was what led you to try creating the custom deserializer.
I'm not entirely sure why the custom deserializer is giving the error it's giving (maybe it doesn't like the fact that it's an inner class: that's just a guess).
The following works fine for me without any custom deserialization:
TestPojo.java:
package jxtest;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class TestPojo {
private final StringProperty myField1 = new SimpleStringProperty();
private final StringProperty myField2 = new SimpleStringProperty();
private int myField3 ;
public final StringProperty myField1Property() {
return this.myField1;
}
public final String getMyField1() {
return this.myField1Property().get();
}
public final void setMyField1(final String myField1) {
this.myField1Property().set(myField1);
}
public final StringProperty myField2Property() {
return this.myField2;
}
public final String getMyField2() {
return this.myField2Property().get();
}
public final void setMyField2(final String myField2) {
this.myField2Property().set(myField2);
}
public int getMyField3() {
return myField3;
}
public void setMyField3(int myField3) {
this.myField3 = myField3;
}
}
Test.java:
package jxtest;
import java.io.IOException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Test {
public static void main(String[] args) throws IOException {
TestPojo item = new TestPojo();
item.setMyField1("Test1");
item.setMyField2("Test2");
item.setMyField3(42);
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(item);
System.out.println(json);
TestPojo readBackIn = mapper.readValue(json, TestPojo.class);
System.out.println(readBackIn.getMyField1());
System.out.println(readBackIn.getMyField2());
System.out.println(readBackIn.getMyField3());
}
}
Output:
{"myField1":"Test1","myField2":"Test2","myField3":42}
Test1
Test2
42
Using jackson-databind 2.8.7.
Upvotes: 2