jackson Java静态final示例层次结构化

ukdjmx9f  于 2023-10-20  发布在  Java
关注(0)|答案(1)|浏览(120)

我有三个班:

public class Base {
  private int code;
  private static final Map<String, Map<Integer, Base>> ALL_MAPS = 
  new HashMap<>();

 protected Base(int code) {
  this.code = code;
  getConstMap(this.getClass()).put(code, this);
}

protected Map<Integer, Base> getConstMap(Class<?> clazz) {
  Map<Integer, Base> res;
  if ((res = ALL_MAPS.get(clazz.getName())) == null) {
     res = new HashMap<>();
     ALL_MAPS.put(clazz.getName(), res);
  }
  return res;
}
//...
}

public class AConstants extends Base {
   public static final AConstants A_1 = new AConstants(1, 
 "sample1");
 public static final AConstants A_2 = new AConstants(2, "sample2");
   //...
   private final String text;
   private AConstants(int code, String text) {
      super(code);
      this.text = text;
   }
}

public class BConstants extends Base {
   public static final BConstants B_1 = new BConstants(1, 
"sample1", "moreText");
   public static final BConstants B_2 = new BConstants(2, 
"sample2", "moreText");
   //...
   private final String text;
   private final String moreText;
   private BConstants(int code, String text, String moreText) {
      super(code);
      this.text = text;
      this.moreText = moreText;
   }
}

我想实现的是在Base类中有一个用于实现(和serealizing)静态final示例的基本方法。显然,我不能这样做smth,因为泛型类型在编译期间无法从静态上下文引用(而且我显然无法获得CONST的类):

@JsonCreator
public static CONST deserialize(@JsonProperty("code") int code) {
    // Should get the class of CONST and retrieve static final instance by code
    return ALL_MAPS.get(CONST.class).get(code);
}

@JsonValue
public Integer serialize() {
    // Return code for static final instance of the necessary class
    return getKeyByValue(ALL_MAPS.get(CONST.class), this);
}

有没有办法和Jackson达成这个目标?或者如果没有,我如何为此编写自定义的序列化器/反序列化器?

0md85ypi

0md85ypi1#

如果有人有类似的用例,我是这样做的。Base类基本上是所有static final示例的占位符(或者我应该称它们为constants)-ALL_MAPS包含key作为扩展Base的类名和值-一个Map键-示例的代码和示例本身作为值。当Base的子类被加载到JVM中时,其中的所有constants(因为它们是static)都被放置在ALL_MAP中。因此,在进行数据库化时,除了将类加载到内存中之外,我只需要一个constant类和它的一个键(code)。我可以像这样在自定义编译器中获取类:https://github.com/FasterXML/jackson-databind/issues/2711
在此之后,剩下的就是将类加载到内存中-我通过反射在任何具有null值的静态字段上调用get方法来实现它,因为我根本不想允许创建const子类的示例。然后-读取包含code的json节点并获得constant
注意:在Base类中,我使用了@JsonDeserialize(using = BaseConstDeserializer.class),其中BaseConstDeserializer是自定义的编译器。
下面是编译器的代码:

public class BaseConstDeserializer<CONST extends BaseConst> extends StdDeserializer<CONST> implements ContextualDeserializer {
private final Class<CONST> deserializedFieldClazz;

protected BaseConstDeserializer(Class<CONST> deserializedFieldClazz) {
    super(BaseConst.class);
    this.deserializedFieldClazz = deserializedFieldClazz;
}

@Override
@SuppressWarnings("unchecked")
public CONST deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JacksonException {
    JsonNode node = jp.getCodec().readTree(jp);
    Integer code = JsonUtils.readSingleNode(node, "code", JsonNode::asInt, ValidUtils::isInteger);
    if (code != null) {
        BaseConst.initConst(deserializedFieldClazz);
        return (CONST) BaseConst.getConstAndClearMap(code, deserializedFieldClazz);
    }
    return null;
}

@Override
@SuppressWarnings("unchecked")
public JsonDeserializer<?> createContextual(DeserializationContext deserializationContext, BeanProperty property) throws JsonMappingException {
    Class<CONST> rawClass = (Class<CONST>) property.getType().getRawClass();
    return new BaseConstDeserializer<>(rawClass);
}
}

这里我能猜到的唯一缺点是我需要自己管理内存使用-每次我解析json时都要清除map。我知道在Spring中,我可以使用@Scope将bean示例的“寿命”设置为请求的范围,但我根本不喜欢在这种情况下创建和拥有这些示例。这可能是一个非正统的方法,但它服务于我的情况,我喜欢的解决方案。无论如何,如果有人看到任何其他潜在的利弊,我想听听。

相关问题