2016-06-10 3 views
0

Я пытаюсь позволить Джексону игнорировать некоторые свойства DTO, однако я не могу показаться, что могу. У меня довольно большой проект со многими зависимостями (Lombok, Spring, GWT, Gemfire и многие другие), , и я не могу изменить эти зависимости (возможно, я могу изменить версии, но это не мой звонок).Джексон игнорирует @Ignore аннотации

я подготовил тестовый случай, здесь:

это мой тестовый класс DTO, то есть карта, которая полезна только на стороне сервера . Копию этого dto сериализуется для отправки в gwt для отображения (реализация не завершена, показаны только соответствующие части ).

import com.fasterxml.jackson.annotation.JsonIgnore; 
import com.fasterxml.jackson.annotation.JsonIgnoreType; 
import lombok.*; 

import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 

@Getter 
@Setter 
@Builder 
@NoArgsConstructor 
@AllArgsConstructor 
@EqualsAndHashCode(of = "id", callSuper = true) 
public class MyClass extends MyAbstractClass { 

    @Getter 
    @Setter 
    @Builder 
    public static class AValueClass { 
     int someInt; 
     String SomeString; 
    } 

    @Data 
    @AllArgsConstructor 
    @NoArgsConstructor 
    @JsonIgnoreType 
    public static class MyJsonIgnoreKeyClass { 
     protected Integer anInt; 
     protected String aString; 
    } 

    @JsonIgnore 
    @Getter(AccessLevel.NONE) @Setter(AccessLevel.NONE) 
    private transient Map<MyJsonIgnoreKeyClass, List<AValueClass>> aMapThatJacksonShouldIgnore = new HashMap<>(); 


    public void addToMap(MyJsonIgnoreKeyClass key, AValueClass value) { 
     List<AValueClass> valueList = aMapThatJacksonShouldIgnore.get(key); 
     if(valueList == null) { 
      valueList = new ArrayList<>(); 
     } 
     valueList.add(value); 
     aMapThatJacksonShouldIgnore.put(key,valueList); 
    } 

    public boolean noMap() { 
     return aMapThatJacksonShouldIgnore == null || aMapThatJacksonShouldIgnore.keySet().isEmpty(); 
    } 

    public void nullifyMap() { 
     aMapThatJacksonShouldIgnore = null; 
    } 

    // other methods operating on maps omitted 
} 

тестовая модель наследует некоторые поля от суперкласса

import lombok.EqualsAndHashCode; 
import lombok.Getter; 
import lombok.Setter; 

import java.util.Date; 

@Setter 
@Getter 
@EqualsAndHashCode(of = "id") 
public class MyAbstractClass { 

    protected String id; 
    protected Date aDay; 
} 

здесь модульные тесты я подготовил

public class MyClassJacksonTest { 

    ObjectMapper om; 

    @Before 
    public void setUp() throws Exception { 
     om = new ObjectMapper().registerModule(new Jdk8Module()); 
     om.setSerializationInclusion(JsonInclude.Include.NON_NULL); 
     om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); 
    } 

    @Test 
    public void testWithMapValues() throws Exception { 
     MyClass testClass = new MyClass(); 
     testClass.setADay(new Date()); 
     testClass.setId(UUID.randomUUID().toString()); 
     testClass.addToMap(
       new MyClass.MyJsonIgnoreKeyClass(1,"test"), 
       new MyClass.AValueClass(1,"test")); 

     StringWriter writer = new StringWriter(); 
     om.writeValue(writer,testClass); 
     writer.flush(); 
     String there = writer.toString(); 
     MyClass andBackAgain = om.readValue(there, MyClass.class); 

     assertTrue(andBackAgain.noMap()); 
    } 

    @Test 
    public void testWithEmptyMaps() throws Exception { 
     MyClass testClass = new MyClass(); 
     testClass.setADay(new Date()); 
     testClass.setId(UUID.randomUUID().toString()); 

     StringWriter writer = new StringWriter(); 
     om.writeValue(writer,testClass); 
     writer.flush(); 
     String there = writer.toString(); 
     MyClass andBackAgain = om.readValue(there, MyClass.class); 

     assertTrue(andBackAgain.noMap()); 
    } 

    @Test 
    public void testWithNullMaps() throws Exception { 
     MyClass testClass = new MyClass(); 
     testClass.setADay(new Date()); 
     testClass.setId(UUID.randomUUID().toString()); 
     testClass.nullifyMap(); 

     StringWriter writer = new StringWriter(); 
     om.writeValue(writer,testClass); 
     writer.flush(); 
     String there = writer.toString(); 
     MyClass andBackAgain = om.readValue(there, MyClass.class); 

     assertTrue(andBackAgain.noMap()); 
    } 

} 

Все тесты терпят неудачу с

com.fasterxml.jackson.databind.JsonMappingException: Can not find a (Map) Key deserializer for type [simple type, class MyClass$MyJsonIgnoreKeyClass] 

Таким образом, вопросы : Почему Джексон пытается найти десериализатор для ключей карты, к которым нельзя получить доступ (поскольку нет геттера и сеттера), и это аннотируется @JsonIgnore? Что еще более важно, как я могу сказать, что не искать десериализаторы?

Это соответствующие зависимости от моего П, если это может быть какой-либо помощь:

<properties> 
    <!-- ... --> 
    <jackson.version>2.7.4</jackson.version> 
</properties> 

<dependencies> 
    <!-- other dependencies omitted --> 
    <dependency> 
     <groupId>com.fasterxml.jackson.core</groupId> 
     <artifactId>jackson-databind</artifactId> 
     <version>${jackson.version}</version> 
    </dependency> 
    <dependency> 
     <groupId>com.fasterxml.jackson.module</groupId> 
     <artifactId>jackson-module-jsonSchema</artifactId> 
     <version>${jackson.version}</version> 
    </dependency> 
    <dependency> 
     <groupId>com.fasterxml.jackson.datatype</groupId> 
     <artifactId>jackson-datatype-jdk8</artifactId> 
     <version>${jackson.version}</version> 
    </dependency> 
    <dependency> 
     <groupId>com.fasterxml.jackson.datatype</groupId> 
     <artifactId>jackson-datatype-jsr353</artifactId> 
     <version>${jackson.version}</version> 
    </dependency> 
    <dependency> 
     <groupId>com.fasterxml.jackson.dataformat</groupId> 
     <artifactId>jackson-dataformat-xml</artifactId> 
     <version>${jackson.version}</version> 
     <exclusions> 
      <exclusion> 
       <groupId>org.codehaus.woodstox</groupId> 
       <artifactId>stax2-api</artifactId> 
      </exclusion> 
     </exclusions> 
    </dependency> 
</dependencies> 

ответ

1

Оказывается, что это случай плохого взаимодействия между Ломбками и Джексоном. Аннотации Lombok @AllArgsConstructor генерирует конструктор, который аннотируется @ConstructorProperties, который, в свою очередь, перечисляет все свойства, объявленные в классе. Это используется Джексоном, когда используется десериализатор по умолчанию. В этом случае отсутствие сеттеров и геттеров и наличие аннотаций @JsonIgnore не учитываются.

Решение просто указать @AllArgsConstructor с установленным атрибутом suppressConstructorProperties истина:

@Getter 
@Setter 
@Builder 
@NoArgsConstructor 
@AllArgsConstructor(suppressConstructorProperties = true) 
@EqualsAndHashCode(of = "id", callSuper = true) 
public class MyClass extends MyAbstractClass { 
    // everything else is unchanged 
+0

Вы также можете подавить генерацию ConstructorProperties для целого пакета или проекта в 'lombok.config':' lombok.anyConstructor.suppressConstructorProperties = false'. –

2

Tricky один, на самом деле. Я думаю, что это происходит, так это то, что вы создаете публичный конструктор всех аргументов с Lombok. При десериализации это тот, который Джексон попытается использовать. Если вы изменили аннотацию для MyClass до

@AllArgsConstructor(access = AccessLevel.PRIVATE) 

... он должен работать нормально. Удачи!

 Смежные вопросы

  • Нет связанных вопросов^_^