我在使用jackson序列化/反序列化java对象结构时有一个非常奇怪的行为...错误发生在e2e-test但是我只能将它提取到具有这个特定的巨大对象的以下测试用例。
二手jackson-version:jackson-databind 2.4.4
以下是测试:
@Test
public void testMapper3() throws JsonParseException, JsonMappingException, IOException{
ProductComponentDTO myComponent = new ProductComponentDTO("Value1", "Value2", null, null, false);
ProductOfferDTO offer = new ProductOfferDTO();
ChosenComponentDTO myChoice = new ChosenComponentDTO();
// Testvariant 3, remove the next line, so serialize and deserialize without the substructure, works!
myChoice.setProductComponentDTO(myComponent);
offer.addChosenComponentDTO(myChoice);
LaraObjectMapper om = new LaraObjectMapper();
// Testvariant 1, serialize and deserialize the hole object => doesn't work
String result = om.writeValueAsString(offer);
System.out.println("Result: " + result);
offer = om.readValue(result, ProductOfferDTO.class);
// Testvariant 2: serialize only a substructure of the object => works!
// String result = om.writeValueAsString(myChoice);
// System.out.println("Result: " + result);
// myChoice = om.readValue(result, ChosenComponentDTO.class);
}
变体1的System.out:
Result: {"@id":1,"numberOfPeople":null,"dateTime":null,"note":null,"state":null,"pk":null,"version":null,"componentNetSum":null,"componentDiscountSum":null,"offerNetSum":null,"offerDiscount":null,"taxSum":null,"grossSum":null,"afterAllDiscountsSum":null,"faultCause":null,"chosenComponentDTO":[{"@id":1,"pk":null,"version":null,"netSum":null,"afterDiscountSum":null,"tax":null,"discount":null,"grossSum":null,"chosenVariantDTO":null,"productComponentDTO":{"@id":1,"name":"Value1","description":"Value2","time":null,"pk":null,"version":null,"price":null,"mustComponent":false,"productDTO":null,"productVariantDTO":null,"chosenComponentDTO":null,"imagesDTO":null,"mainPicture":null,"changeManager":null},"productOfferDTO":null,"changeManager":null}],"productDTO":null,"productOfferCustomerDTO":null,"productBonusMalusDTO":null,"changeManager":null}
FAILED: testMapper3
com.fasterxml.jackson.databind.JsonMappingException: No _valueDeserializer assigned
at [Source: {"@id":1,"numberOfPeople":null,"dateTime":null,"note":null,"state":null,"pk":null,"version":null,"componentNetSum":null,"componentDiscountSum":null,"offerNetSum":null,"offerDiscount":null,"taxSum":null,"grossSum":null,"afterAllDiscountsSum":null,"faultCause":null,"chosenComponentDTO":[{"@id":1,"pk":null,"version":null,"netSum":null,"afterDiscountSum":null,"tax":null,"discount":null,"grossSum":null,"chosenVariantDTO":null,"productComponentDTO":{"@id":1,"name":"Value1","description":"Value2","time":null,"pk":null,"version":null,"price":null,"mustComponent":false,"productDTO":null,"productVariantDTO":null,"chosenComponentDTO":null,"imagesDTO":null,"mainPicture":null,"changeManager":null},"productOfferDTO":null,"changeManager":null}],"productDTO":null,"productOfferCustomerDTO":null,"productBonusMalusDTO":null,"changeManager":null}; line: 1, column: 456] (through reference chain: com.mleitner.product.service_contract.ProductOfferDTO["chosenComponentDTO"]->com.mleitner.product.service_contract.ChosenComponentDTOList[0]->com.mleitner.product.service_contract.ChosenComponentDTO["productComponentDTO"]->com.mleitner.product.service_contract.ProductComponentDTO["name"])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:770)
at com.fasterxml.jackson.databind.deser.impl.FailingDeserializer.deserialize(FailingDeserializer.java:27)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:538)
at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:106)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:306)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeWithObjectId(BeanDeserializerBase.java:1036)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:122)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:538)
at com.fasterxml.jackson.databind.deser.impl.ObjectIdReferenceProperty.deserializeSetAndReturn(ObjectIdReferenceProperty.java:76)
at com.fasterxml.jackson.databind.deser.impl.ObjectIdReferenceProperty.deserializeAndSet(ObjectIdReferenceProperty.java:67)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:306)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeWithObjectId(BeanDeserializerBase.java:1036)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:122)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:232)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:206)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:25)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:538)
at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:106)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:306)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeWithObjectId(BeanDeserializerBase.java:1036)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:122)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3066)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2161)
at com.mleitner.businessmaximizer.webservice.ExceptionsHaveDefaultConstructorTest.testMapper3(ExceptionsHaveDefaultConstructorTest.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
at org.testng.TestRunner.privateRun(TestRunner.java:767)
at org.testng.TestRunner.run(TestRunner.java:617)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
at org.testng.SuiteRunner.run(SuiteRunner.java:240)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
at org.testng.TestNG.run(TestNG.java:1057)
at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)
变体2的System.out:
Result: {"@id":1,"pk":null,"version":null,"netSum":null,"afterDiscountSum":null,"tax":null,"discount":null,"grossSum":null,"chosenVariantDTO":null,"productComponentDTO":{"@id":1,"name":"Value1","description":"Value2","time":null,"pk":null,"version":null,"price":null,"mustComponent":false,"productDTO":null,"productVariantDTO":null,"chosenComponentDTO":null,"imagesDTO":null,"mainPicture":null,"changeManager":null},"productOfferDTO":null,"changeManager":null}
PASSED: testMapper3
变体3的System.out:
Result: {"@id":1,"numberOfPeople":null,"dateTime":null,"note":null,"state":null,"pk":null,"version":null,"componentNetSum":null,"componentDiscountSum":null,"offerNetSum":null,"offerDiscount":null,"taxSum":null,"grossSum":null,"afterAllDiscountsSum":null,"faultCause":null,"chosenComponentDTO":[{"@id":1,"pk":null,"version":null,"netSum":null,"afterDiscountSum":null,"tax":null,"discount":null,"grossSum":null,"chosenVariantDTO":null,"productComponentDTO":null,"productOfferDTO":null,"changeManager":null}],"productDTO":null,"productOfferCustomerDTO":null,"productBonusMalusDTO":null,"changeManager":null}
PASSED: testMapper3
因此变体2和3正在工作=>所以每个对象结构都可以序列化,但它们不能序列化在一起。为什么? 我也试图解决问题,复制所有使用的对象以减少对象属性,直到我找到错误但在文件副本之后不再发生错误。然后我删除了所有maven repo条目并进行了新的构建(虽然可能是我正在使用一些旧文件),但也没有帮助。然后我调试了测试,错误发生在元素名称(但这是一个常见的字符串,所以为什么不工作?!)。
我序列化的对象包含列表。这个列表看起来像这样:
public class ChosenComponentDTOList
extends ArrayList <ChosenComponentDTO>{
public ChosenComponentDTOList(){
}
public ChosenComponentDTOList(List<ChosenComponentDTO> values){
super();
if (values != null)
this.addAll(values);
}
}
这是使用过的ObjectMapper:
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
public class LaraObjectMapper extends ObjectMapper{
/**
*
*/
private static final long serialVersionUID = -4831947927759735004L;
public LaraObjectMapper() {
this.setVisibilityChecker(
getSerializationConfig().
getDefaultVisibilityChecker().
withFieldVisibility(JsonAutoDetect.Visibility.ANY).
withGetterVisibility(JsonAutoDetect.Visibility.NONE).
withSetterVisibility(JsonAutoDetect.Visibility.NONE).
withCreatorVisibility(JsonAutoDetect.Visibility.NONE).
withIsGetterVisibility(JsonAutoDetect.Visibility.NONE));
this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
this.setAnnotationIntrospector(new LaraJacksonAnnotationIntrospector());
}
}
使用的annotationintrospector:
public class LaraJacksonAnnotationIntrospector extends
JacksonAnnotationIntrospector {
/**
*
*/
private static final long serialVersionUID = 1250247138609942147L;
@Override
public ObjectIdInfo findObjectIdInfo(final Annotated ann) {
if (BaseDTO.class.isAssignableFrom(ann.getRawType())) {
// this is needed for recursive structures
return new ObjectIdInfo(PropertyName.construct("@id", null),
ann.getRawType(),
ObjectIdGenerators.IntSequenceGenerator.class, null);
}
return super.findObjectIdInfo(ann);
}
@Override
public TypeResolverBuilder<?> findTypeResolver(MapperConfig<?> config,
AnnotatedClass ac, JavaType baseType) {
//every abstract class must serialize the concrete class => otherwise deserialize of the abstract class is not possible
if (__isAbstract(baseType.getRawClass()) && __handledClass(baseType.getRawClass())){
StdTypeResolverBuilder typeResolverBuilder = new StdTypeResolverBuilder();
typeResolverBuilder.typeProperty("@class");
typeResolverBuilder.inclusion(As.PROPERTY);
typeResolverBuilder.init(Id.CLASS, null);
return typeResolverBuilder;
}
return super.findTypeResolver(config, ac, baseType);
}
private boolean __handledClass(Class<?> clazz) {
return BaseDTO.class.isAssignableFrom(clazz) ||
FinderAttribute.class.isAssignableFrom(clazz) ||
ValidationError.class.isAssignableFrom(clazz) ||
AbstractChangeManager.class.isAssignableFrom(clazz);
}
private boolean __isAbstract(Class<?> clazz) {
return Modifier.isAbstract(clazz.getModifiers());
}
}
所以任何人都知道什么是错的?感谢您的时间和支持。
KR
更新 如果我删除ObjectIdInfo,那么它的工作原理。但它没有解决方案,因为我需要这些信息用于递归结构。
答案 0 :(得分:1)
我仍然不知道为什么会发生这种异常,但是我为每个dto使用了StdTypeResolverBuilder,我将其序列化然后运行。
可能会帮助那些有同样问题的人......