2016-06-10 125 views
0

我想讓傑克遜忽略DTO的某些屬性,但是我似乎無法做到。 我有一個相當大的項目與許多依賴項(龍目,春季,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] 
是失敗

所以問題是: 爲什麼傑克遜試圖爲無法訪問的地圖的鍵找到解串器(因爲沒有getter和setter),並且用@JsonIgnore註解了? 更重要的是,我怎麼能告訴它不要搜索反序列化器?

這些都是我的POM相關的依賴關係,如果它可以是任何幫助:

<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

事實證明,這是龍目島和傑克遜之間的互動不良的情況。 龍目島註釋@AllArgsConstructor生成一個構造函數,該構造函數使用@ConstructorProperties進行註釋,該構造函數反過來列出在該類中聲明的所有屬性。 當默認的解串器被使用時,Jackson就會使用它。 在這種情況下,沒有考慮setter和getter的存在以及@JsonIgnore註釋的存在。

解決方法是指定@AllArgsConstructor與屬性suppressConstructorProperties設置爲true:

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

您還可以在'lombok.config'中限制整個包或項目的ConstructorProperties的生成:'lombok.anyConstructor.suppressConstructorProperties = false'。 –

2

棘手的,確實如此。我認爲正在發生的事情是你正在用Lombok產生一個公開的所有參數構造函數。反序列化時,這是Jackson將嘗試使用的那個。如果您將您的MyClass註釋更改爲

@AllArgsConstructor(access = AccessLevel.PRIVATE) 

...應該可以正常工作。祝你好運!