【问题标题】:java.beans.ConstructorProperties in Jackson 2杰克逊 2 中的 java.beans.ConstructorProperties
【发布时间】:2014-09-10 12:43:53
【问题描述】:

我的域对象使用lombok 进行了增强,它为不可变对象的构造函数生成 java.beans @ConstructorProperties 注释。

现在在我的前端工件中,我想使用Jackson 2 将这些对象序列化为 JSON。 对于 Jackson 1,这可以使用 Jackson Extensions 来完成。杰克逊2也有这样的解决方案还是我必须自己写?

我的主要问题是我想让我的域对象前端不可知,所以我不想用 Jackson 注释污染它们。

不:Java 8 parameter names 不是一个选项,因为我暂时坚持使用 Java 7。

【问题讨论】:

标签: java jackson javabeans lombok


【解决方案1】:

Sean Patrick Floyd 已经编写了一个解决方案,但我发布我的解决方案是因为他是专有的。这是一个 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());

【讨论】:

    【解决方案2】:

    正如其他人所说,Jackson 现在支持 @ConstructorProperties - 不幸。因为它把事情搞砸了。

    Jackson 应用的逻辑非常不幸。如果存在多个@ConstructorProperties 带注释的构造函数,它将通过具有最多参数的一个 创建对象。行动。这是一个问题,尤其是对于使用@ConstructorProperties 注释 all 构造函数的 Lombok。但无论如何,这个注释不仅仅适用于杰克逊。为任何可能使用此信息的代码检查工具注释每个构造函数是有意义的。龙目岛就在这里。

    想象以下物体:

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

    这里 Jackson 将始终使用全参数构造函数,因为它带有 @ConstructorProperties 注释并且具有大多数参数。

    这也意味着如果您在 JSON 对象中仅设置 value2,value1 将变为 null。不是你所期望的。

    结论:当前行为(与 Lombok 一起使用或注释多个构造函数时)不允许简单的类级默认值。

    解决方法: @AllArgsConstructor(suppressConstructorProperties=true) - 但它声称很快就会被弃用,因为它只是为了兼容 java 1.5 的目的。

    【讨论】:

    • 对于它的价值:我不再使用 Lombok,因为 immutables.github.io 在几乎所有方面都优于。但是感谢您的回答,这对剩余的 Lombok 用户来说是一个有效的贡献。
    【解决方案3】:

    这个问题终于在 Jackson 2.7 中得到解决,@ConstructorProperties 现在支持开箱即用。

    见https://github.com/FasterXML/jackson-databind/issues/905

    【讨论】:

      【解决方案4】:

      恐怕你必须自己为 Jackson2 编写一个类似的包装器。

      【讨论】:

      • ^^这是我的同事在取笑我(*sniff*)
      • 我现在确实写了那个包装器,但不幸的是它是专有的,所以我不能在这里发布。
      猜你喜欢
      • 2017-05-27
      • 2020-04-12
      • 1970-01-01
      • 2018-08-10
      • 1970-01-01
      • 1970-01-01
      • 2011-08-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多