Java 由于杰克逊,二进制序列化失败
Java binary serializing fails because of jackson
我使用 jackson 2 将 json 转换为 java object。到目前为止,一切都很好。但我也使用 hazelcast 在集群中分发 objects。因此所有 bean 都必须是 java.io.Serializable。当我像这样从 json 读取 Object 时:
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);
我将从 hazelcast 得到一个例外:
java.io.NotSerializableException: com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer
我想知道 com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer 是从哪里来的,因为 Object 是一个普通的 java bean(但使用继承)。
我的摘要 class 是:
@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();
}
}
而我的 child 是:
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;
}
}
我不知道为什么 serailizer 甚至会尝试序列化 mixin,因为它们不是 bean 的一部分,但它们在这里(是的,我也试图让它们可序列化,只是作为测试,运气不好) :
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();
}
}
我是 1 名代表,无法发表评论。所以我必须提出一个建议作为答案;-)。
也许其中一个注释确实将 TypeWrappedDeserializer 实例作为私有 属性 注入到 AbstractBean 中。也许作为反序列化机制的提示。
能不能用反射检查创建的对象来验证一下?
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());
}
如果您在列表中找到合适的类型,Class 是字节码增强添加的。
愚蠢的我!序列化链中的某处是一个完全不必要的 ObjectMapper 对象。但是很难找到,因为真正的原因不是 Posting 对象,而是另一个对象。但是 Stacktrace 和 com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer Exception 完全没有领先! ...集群软件有时调试起来真的很痛苦:-)
我使用 jackson 2 将 json 转换为 java object。到目前为止,一切都很好。但我也使用 hazelcast 在集群中分发 objects。因此所有 bean 都必须是 java.io.Serializable。当我像这样从 json 读取 Object 时:
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);
我将从 hazelcast 得到一个例外:
java.io.NotSerializableException: com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer
我想知道 com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer 是从哪里来的,因为 Object 是一个普通的 java bean(但使用继承)。
我的摘要 class 是:
@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();
}
}
而我的 child 是:
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;
}
}
我不知道为什么 serailizer 甚至会尝试序列化 mixin,因为它们不是 bean 的一部分,但它们在这里(是的,我也试图让它们可序列化,只是作为测试,运气不好) :
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();
}
}
我是 1 名代表,无法发表评论。所以我必须提出一个建议作为答案;-)。
也许其中一个注释确实将 TypeWrappedDeserializer 实例作为私有 属性 注入到 AbstractBean 中。也许作为反序列化机制的提示。
能不能用反射检查创建的对象来验证一下?
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());
}
如果您在列表中找到合适的类型,Class 是字节码增强添加的。
愚蠢的我!序列化链中的某处是一个完全不必要的 ObjectMapper 对象。但是很难找到,因为真正的原因不是 Posting 对象,而是另一个对象。但是 Stacktrace 和 com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer Exception 完全没有领先! ...集群软件有时调试起来真的很痛苦:-)