与杰克逊的JSON - 每个对象可序列化,异常

时间:2015-07-20 12:49:11

标签: java json jackson

我在使用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,那么它的工作原理。但它没有解决方案,因为我需要这些信息用于递归结构。

1 个答案:

答案 0 :(得分:1)

我仍然不知道为什么会发生这种异常,但是我为每个dto使用了StdTypeResolverBuilder,我将其序列化然后运行。

可能会帮助那些有同样问题的人......