【问题标题】:How to make Jackson to inject the Generic Class into a bean?如何让杰克逊将泛型类注入 bean?
【发布时间】:2019-10-25 23:48:04
【问题描述】:

假设我们有一个像这样的 bean:

public class Response<T> {

    private T data;
    private double executionDuration;
    private boolean success;
    private String version;

    //HOW TO Make Jackson to inject this?
    private Class<T> dataClass;

    public Optional<T> getData() {
        return Optional.ofNullable(data);
    }

    public double getExecutionDuration() {
        return executionDuration;
    }

    public Class<T> getDataClass() {
        return dataClass;
    }

    public String getVersion() {
        return version;
    }

    public boolean isSuccess() {
        return success;
    }
}

反序列化是这样发生的:

objectMapper.readValue(json, new TypeReference<Response<SomeClass>>() {});

我可以让 Jackson 将“SomeClass”类注入到我的 bean 中吗?我认为注入类型引用本身也可以。

【问题讨论】:

  • 你能检查一下吗 -> stackoverflow.com/questions/11664894/…
  • @VinayVeluri in json 我对“dataClass”没有参考。杰克逊如何知道的唯一方法是类型引用。这就是为什么我想知道杰克逊是否可以注入这些信息。
  • 它不能这样做,您可能想自己通过读取一个带有类作为字符串的值,然后使用 Class.forName 加载该类。不仅杰克逊,而且您自己也不能假设您知道该课程(该课程可以类加载)。然后用公认的类再次解析它
  • 为什么不打电话给data.getClass()
  • 你可以在getDataClass方法中添加null检查:data == null ? data.getClass() : Void.class

标签: java json jackson


【解决方案1】:

如果不希望将类信息保存在 json 中并使用@JsonTypeInfo,我建议使用@JacksonInject

  public class Response<T> {
    private T data;
    private double executionDuration;
    private boolean success;
    private String version;

    @JacksonInject("dataClass")
    private Class<T> dataClass;

    public Optional<T> getData() {
      return Optional.ofNullable(data);
    }

    public double getExecutionDuration() {
      return executionDuration;
    }

    public Class<T> getDataClass() {
      return dataClass;
    }

    public String getVersion() {
      return version;
    }

    public boolean isSuccess() {
      return success;
    }
  }

反序列化看起来像:

ObjectMapper mapper = new ObjectMapper();
InjectableValues.Std injectable = new InjectableValues.Std();
injectable.addValue("dataClass", SomeClass.class);
mapper.setInjectableValues(injectable);
final Response<Integer> response = mapper.readValue(json, new TypeReference<Response<SomeClass>>() { });

【讨论】:

  • 谢谢。有趣的问题是如何根据类型引用自动注入类?
  • 不是因为type erasure而不可能吗?
  • @AustinSchäfer - Jackson 有 TypeReference,所以它应该在反序列化期间知道哪个参数类在参数化的 Response 类中。
【解决方案2】:

这对我有用;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
public class Entity<T> {
    private T data;
    @JsonSerialize(converter = ClassToStringConverter.class)
    @JsonDeserialize(converter = StringToClassConverter.class)
    private Class<T> dataClass;
}

import com.fasterxml.jackson.databind.util.StdConverter;

public class ClassToStringConverter extends StdConverter<Class<?>, String> {

    public String convert(Class<?> aClass) {
//        class java.lang.Integer
        return aClass.toString().split("\\s")[1];
    }
}

import com.fasterxml.jackson.databind.util.StdConverter;

public class StringToClassConverter extends StdConverter<String, Class<?>> {

    public Class<?> convert(String s) {
        try {
            return Class.forName(s);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}

主要的;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;

public class Main {

    public static void main(String[] args) throws IOException {
        Entity<Integer> data = new Entity<Integer>();
        data.setData(5);
        data.setDataClass(Integer.class);

        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writeValueAsString(data);

        Entity<Integer> jsonData = mapper.readValue(json, new TypeReference<Entity<Integer>>() {});
        System.out.println(jsonData.getData());
        System.out.println(jsonData.getDataClass().getCanonicalName());
    }
}

但是,也许不保存类类型,而是使用方法从数据中获取类型会更好?

public Class<T> getType() {
    return (Class<T>) data.getClass();
}

【讨论】:

    【解决方案3】:
    public class Response<T> {
        private T data;
    
        // other fields & methods
    
        public Class getType() {
            return Optional.ofNullable(data).map(Object::getClass).orElse(Void.class);
        }
    
        public Optional<Class> getSafeType() {
            return Optional.ofNullable(data).map(Object::getClass);
        }
    }
    

    超级简单,不用修Jackson,NPE安全...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多