4

I use jackson 2 to convert json into a java object. So far so good. But I also use hazelcast to distribute the objects in a cluster. Therefore all beans have to be java.io.Serializable. When I read the Object from json like so:

ObjectMapper mapper = new ObjectMapper();
mapper.addMixInAnnotations(AbstractBean.class, MongoIdMixIn.class);

// this is to prevent from failing on missing type class property: @JsonProperty("@class")
Object tgtObject = targetClass.newInstance();
mapper.readerForUpdating(tgtObject).readValue(dbo.toString());

// put into hazelcast map
target.put(dbo.get(keyColumn), tgtObject); 

I will get an exception from hazelcast:

java.io.NotSerializableException: com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer

I am wondering where the com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer is coming from since the Object is a plain java bean (but using inheritance).

My Abstract class is:

@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@javaClass")
public abstract class AbstractBean implements Serializable {
    @JsonIgnore public static final transient IMarkupParser MARKUP_PARSER = new WikiMarkupParser();

    @JsonProperty("id")
    private String id;

    @JsonProperty("@class")
    private String clazz;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getClazz() {
        return this.getClass().getSimpleName();
    }
}

And my child is:

public class Posting extends AbstractBean {
    private String postingSource;
    private String languageCode;

    public String getPostingSource() {
        return postingSource;
    }

    public void setPostingSource(String postingSource) {
        this.postingSource = postingSource;
    }

    public String getLanguageCode() {
        return languageCode;
    }

    public void setLanguageCode(String languageCode) {
        this.languageCode = languageCode;
    }
}

I have no Idea why the serailizer would even try to serialize the mixins since the are not part of the bean but here they are (yes I have tried to make them serializable too, just as a test, no luck):

public interface IdMixins extends Serializable {
}

public interface MongoIdMixIn extends IdMixins {
    @JsonProperty("_id")
    @JsonSerialize(using = MongoIdSerializer.class)
    public String getId();

    @JsonProperty("_id")
    @JsonDeserialize(using = MongoIdDeserializer.class)
    public void setId(String id);
}

public class MongoIdDeserializer extends JsonDeserializer<String> implements Serializable {
    private static final long serialVersionUID = -5404276857799190647L;

    @Override
    public String deserialize(JsonParser jp, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        String value = null;

        String tmp = jp.getText(); // {
        validate(jp, tmp,"{");
        int curly = 1;

        while (jp.nextToken() != null) {
            String v = jp.getText();

            if (v.equals("{")) curly++;

            if (v.equals("$oid")) {
                jp.nextToken();
                value = jp.getText();
            }

            if (v.equals("}")) curly--;
            if (curly<=0) return value;
        }

        return null;
    }

    private void validate(JsonParser jsonParser, String input, String expected) throws JsonProcessingException {
        if (!input.equals(expected)) {
            throw new JsonParseException("Unexpected token: " + input, jsonParser.getTokenLocation());
        }
    }
}

public class MongoIdSerializer extends JsonSerializer<String> implements Serializable {
    private static final long serialVersionUID = 3435689991839324194L;

    @Override
    public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
        jsonGenerator.writeStartObject();
        jsonGenerator.writeFieldName("$oid");
        jsonGenerator.writeString(s);
        jsonGenerator.writeEndObject();
    }
}
2
  • Can you provide a full Jackson sample? What are those mixins? What is targetClass? Commented May 19, 2015 at 16:03
  • @SotiriosDelimanolis the target class is just a class from name (config) and in this case is just the Posting.class. I have added the mixin classes to my question Commented May 19, 2015 at 16:30

2 Answers 2

1

Stupid me! Somewhere in the serialization chain was a completely unnecessary ObjectMapper object. But it was hard to find because not the Posting object was the real reason, instead it was another object. But the Stacktrace and the com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer Exception were completely miss leading! ... clustered software is sometimes really painful to debug :-)

Sign up to request clarification or add additional context in comments.

Comments

0

I'm 1 Rep. Point away from being able to comment. So I have to make a suggestion as an answer ;-).

Perhaps one of the Annotations do inject an instance of TypeWrappedDeserializer as a private property into the AbstractBean. Maybe as hint for the deserialization mechanism.

Could you inspect the created object with reflection to verify?

for (Field field : tgtObject.getClass().getDeclaredFields() )
{
   // you can replace this by your logging method
   System.out.println("Field: " + field.getName() + ":" + field.getType());
}
for (Field field : tgtObject.getClass().getSuperclass().getDeclaredFields() )
{
   // you can replace this by your logging method
   System.out.println("Field: " + field.getName() + ":" + field.getType());
}

If you find the apropriate type in the listing the Class was added by Byte Code Enhancement.

3 Comments

I try it out myself. It did not work. Ok, the Annotations are not to blame. But TypeWrapeDeserializer (the name) points me to annother guess: Perhaps the method readerForUpdating(tgtObject) injects this Deserializer. But that's something I can not check.
The mixin annotation method can also provide Annotation the affect the byte code.
Neither refelction nor the IDE debugger is showing any wired fields

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.