如何在 Java 中声明任何 class 类型的变量或对象

How to declare a variable or Object of any class type in Java

我对 Java 很陌生,我正在尝试使用 Jackson 反序列化 JSON,但我在声明 Object/Variable 类型方面遇到了一些小问题。我会提供所有代码然后解释问题以便于理解。

我有一个具有所需类型值的枚举:

public enum IdentifierTypeValues {
    Type1,                  
    Type2,                      
    Type3,                  
    //Constructor and Getter of enum values
}

然后对于这些 type 中的每一个,我有不同的 classes,它们将具有不同的输入并执行完全不同类型的过程:

public class GenerateType1 {
    private String name;
    private String age;
    //Getter and Setter
    //Some required process based on these values
}

public class GenerateType2 {
    private String address;
    private String city;
    private String country;
    //Getter and Setter
    //Some required process based on these values
}

public class GenerateType3 {
    private String firstName;
    private String lastName;
    private String fullName;
    //Getter and Setter
    //Some required process based on these values
}

现在我有一个包装器 class 用于这些类型的 classes,它将采用基于 enumtypeInfo 值的 type。我希望 typeInfo 值是任何基于 class 的类型,如下所示:

public class TypeSyntax {
    private IdentifierTypeValues indeitiferType;
    private GenerateType1 / GenerateType2 / GenerateType3 identifierTypeValues;

    //Here the identifierTypeValues can have the values for anytype
    //How to declare a variable of any of these class type?
}

这是我的 JSON 将用于反序列化的 class。我知道我可以添加这 3 种类型的包装器 class 并为此提供该包装器 class 作为类型 class。像这样:

public class WrapperClass{
    private GenerateType1 type1;
    private GenerateType2 type2;
    private GenerateType3 type3;
}

public class TypeSyntax{
    private IdentifierTypeValues indeitiferType;
    private WrapperClass identifierTypeValues;
    //But using this approach will change my JSON structure which I do not want to do.
}

我的 JSON 结构是这样的,我想以同样的方式保持它。

{
    "indeitiferType":"Type1",
    "identifierTypeValues":{
      "name":"Batman",
      "age":"2008"
    }
}

有没有办法声明多类型的变量class?或通过保持 json 格式相同来处理此问题的任何更好方法?我尝试搜索,但我无法搜索到底是什么,所以任何帮助都会非常有用。

因为类型标识符存在于与其他属性不同的级别,所以需要包装器 class TypeSyntax。有几个开放的功能请求向 Jackson 添加包装功能,例如https://github.com/FasterXML/jackson-databind/issues/512

幸运的是,Jackson 通过 @JsonTypeInfo@JsonSubTypes 注释支持多态性。

包装器 class 应如下所示:

public class TypeSyntax {
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
            include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
            property = "identifierType")
    private GenerateTypeBase identifierTypeValues;

// getters and setters (omitted for brevity)
}

GenerateTypeBase是普通的parentclass

@JsonSubTypes({  
        @JsonSubTypes.Type(value = GenerateType1.class, name = "Type1"),
        @JsonSubTypes.Type(value = GenerateType2.class, name = "Type2"),  
})  
public abstract class GenerateTypeBase {  
    private String name;  
    private String age;  

// getters and setters (omitted for brevity)
}

在此不同的childrenclasses将基于identifierType属性进行实例化。 children 必须扩展此基础 class:

public class GenerateType2 extends GenerateTypeBase {  

// additional properties

}

在简短的测试中它将是:

@Test  
void wrapperTest() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    GenerateType2 a = new GenerateType2();
    a.setName("Foo");
    a.setAge("13");
    TypeSyntax w = new TypeSyntax();
    w.setIdentifierTypeValues(a);
    String json = mapper.writeValueAsString(w);
    System.out.println(json);  
}

和输出:

{
    "identifierTypeValues":
    {
        "name":"Foo",
        "age":"13"
    },
    "identifierType":"Type2"
}

反序列化

@Test  
void wrapperTest() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    String input = "{\"identifierTypeValues\": \"name\":\"Foo\",\"age\":\"13\"},\"identifierType\":\"Type2\"}";
    TypeSyntax w = mapper.readValue(new StringReader(input), TypeSyntax.class);
    assertAll(  
        () -> assertEquals(GenerateType2.class, o.getIdentifierTypeValues().getClass()),
        () -> assertEquals("13", o.getIdentifierTypeValues().getAge())
    );
}

如果您想要更大的灵活性,您可以编写自定义(反)序列化器和/或自定义解析器。使用自定义 TypeIdResolver 可以以编程方式将标识符转换为类型,而不是在 @JsonSubTypes

中使用“key-value 对”