2014-09-10 68 views
2

我的域對象使用lombok進行了增強,它爲不可變對象的構造函數生成java.beans @ConstructorProperties註釋。Jackson的java.beans.ConstructorProperties 2

現在在我的前端工件中,我想使用Jackson 2將這些對象序列化爲JSON。對於Jackson 1,這可以使用Jackson Extensions完成。傑克遜2還有這樣的解決方案嗎?還是我必須自己寫?

我的主要問題是我想讓我的域對象前端不可知,所以我不想用Jackson註釋污染它們。

而且沒有:Java 8 parameter names不是一個選項,因爲我暫時停留在Java 7中。

+1

Jackson 2.7添加了對構造函數屬性的支持:https://github.com/FasterXML/jackson-databind/issues/905 – Thomas 2016-04-08 18:37:17

+0

@Thomas爲什麼不把它寫成答案?它值得更多的關注 – 2016-04-09 09:22:24

回答

1

恐怕你得爲Jackson2自己寫一個類似的包裝。

+1

^^這是我的同事嘲笑我(\ *嗅探* *) – 2014-09-10 13:08:15

+0

我現在寫了這個包裝,但不幸的是它是專有的,所以我不能在這裏發佈它。 – 2014-09-10 16:11:03

4

肖恩帕特里克弗洛伊德已經寫了一個解決方案,但我張貼我的解決方案,因爲他是專有的。這是一個Jackson模塊,它使用AnnotationIntrospector創建一個構造函數,並使用@ConstructorProperties註釋一個jackson @JsonCreator。

import com.fasterxml.jackson.annotation.JsonProperty; 
import com.fasterxml.jackson.core.json.PackageVersion; 
import com.fasterxml.jackson.databind.Module; 
import com.fasterxml.jackson.databind.introspect.Annotated; 
import com.fasterxml.jackson.databind.introspect.AnnotatedConstructor; 
import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector; 
import com.fasterxml.jackson.databind.module.SimpleModule; 
import java.beans.ConstructorProperties; 
import java.lang.annotation.Annotation; 
import java.lang.reflect.Constructor; 

public class ConstructorPropertiesModule extends SimpleModule { 

    public ConstructorPropertiesModule() { 
    super(PackageVersion.VERSION); 
    } 

    @Override 
    public void setupModule(Module.SetupContext context) { 
    super.setupModule(context); 
    context.insertAnnotationIntrospector(new ConstructorPropertiesAnnotationIntrospector()); 
    } 

    public static class ConstructorPropertiesAnnotationIntrospector extends NopAnnotationIntrospector { 

    @Override 
    public boolean hasCreatorAnnotation(Annotated a) { 
     if (!(a instanceof AnnotatedConstructor)) { 
     return false; 
     } 

     AnnotatedConstructor ac = (AnnotatedConstructor) a; 

     Constructor<?> c = ac.getAnnotated(); 
     ConstructorProperties properties = c.getAnnotation(ConstructorProperties.class); 

     if (properties == null) { 
     return false; 
     } 

     for (int i = 0; i < ac.getParameterCount(); i++) { 
     final String name = properties.value()[i]; 
     final int index = i; 
     JsonProperty jsonProperty = new JsonProperty() { 

      @Override 
      public String value() { 
      return name; 
      } 

      @Override 
      public boolean required() { 
      return false; 
      } 

      @Override 
      public Class<? extends Annotation> annotationType() { 
      return JsonProperty.class; 
      } 

      @Override 
      public int index() { 
      return index; 
      } 

     }; 
     ac.getParameter(i).addOrOverride(jsonProperty); 
     } 
     return true; 
    } 

    } 

} 

模塊,然後就可以註冊一個對象映射器使用@ConstructorProperties註釋,反序列化JSON:

ObjectMapper m = new ObjectMapper(); 
m.registerModules(new ConstructorPropertiesModule()); 
+0

這不再適用於傑克遜2.5.3。 – 2015-05-07 17:17:35

3

正如其他人說傑克遜現在支持@ConstructorProperties - 可惜的。因爲它搞砸了東西。

傑克遜應用的邏輯非常不幸。如果存在多個@ConstructorProperties帶註釋的構造函數,它將通過一個創建對象,大多數參數爲。行動。這是一個問題,尤其是在龍目島上,其註釋所有構造函數與@ConstructorProperties。但無論如何,這個註釋並不僅限於傑克遜。爲任何可能使用此信息的代碼檢查工具註釋每個構造函數是有意義的。龍目島就在這裏。

試想以下對象:

@Data 
@Builder 
@NoArgsConstructor // for Jackson 
@AllArgsConstructor // for builder 
public class MyDto { 
    private Type1 value1 = Type1.NONE; 
    private Type2 value2; 
} 

這裏傑克遜總是會使用所有參數的構造,因爲它是標註有@ConstructorProperties並擁有大部分參數。

這也意味着如果您在您的JSON對象中只設置value2,則value1將變爲null。不是你所期望的。

結論:當前行爲(當與Lombok一起使用或註釋多個構造函數時)不允許簡單的類級缺省值。

解決方法:@AllArgsConstructor(suppressConstructorProperties=true) - 但這聲稱,因爲它的存在只是爲Java 1.5的兼容性的目的將很快過時。

+0

對於它的價值:我不再使用龍目島,因爲https://immutables.github.io/在幾乎所有的點上都優越。但是,感謝您的回答,這是剩下的龍目島用戶的有效貢獻。 – 2016-10-09 02:03:20