Java泛型:将嵌套json响应映射到Java对象

Java泛型:将嵌套json响应映射到Java对象,java,generics,Java,Generics,情景: 我正在使用一个不寻常的外部API,其中每个属性都是一个具有多个值的映射。 为了将这个响应转换成简单的Java对象,我不得不进行一些不必要的拆箱。下面是一个典型的java类。正如您所看到的,我是如何从响应中解包数据并将它们映射到我的java类的: import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import java.time.LocalDate; import java.util.Map;

情景: 我正在使用一个不寻常的外部API,其中每个属性都是一个具有多个值的映射。 为了将这个响应转换成简单的Java对象,我不得不进行一些不必要的拆箱。下面是一个典型的java类。正如您所看到的,我是如何从响应中解包数据并将它们映射到我的java类的:

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;

import java.time.LocalDate;
import java.util.Map;

import static com.my.util.BaseUtil.unbox;

@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PartyDetailsDto {

    private String partyId;
    private String partyType;
    private String title;
    private String firstName;
    private String lastName;
    private String middleName;
    private LocalDate dateOfBirth;

    @JsonProperty(value = "partyId")
    public void unboxPartyId(Map<String, String> data) {
        this.partyId = unbox(data, "evidenceId");
    }

    @JsonProperty(value = "partyType")
    public void unboxPartyType(Map<String, String> partyType) {
        this.partyType = unbox(partyType, "value");
    }

    @JsonProperty(value = "individual")
    public void unboxIndividualDetails(Map<String, Object> individual) {
        Map<String, String> title = (Map<String, String>) individual.get("title");
        Map<String, String> firstName = (Map<String, String>) individual.get("firstName");
        Map<String, String> lastName = (Map<String, String>) individual.get("lastName");
        Map<String, String> middleName = (Map<String, String>) individual.get("middleName");
        Map<String, String> dateOfBirth = (Map<String, String>) individual.get("birthDate");

        this.title = unbox(title, "value");
        this.firstName = unbox(firstName, "value");
        this.lastName = unbox(lastName, "value");
        this.middleName = unbox(middleName, "value");
        this.dateOfBirth = LocalDate.parse(unbox(dateOfBirth, "value"));
    }
}
我正在尝试将上述方法转换为通用方法,在该方法中,我可以动态指定返回类型,并相应地强制转换返回的数据

有人能帮我做一个吗

我试过这个:

public static <T> T unbox(Map<String, String> data, String key, Class<T> type) {
        if (data != null && data.containsKey(key)) {
            return (type) data.get(key);
        }
        return null;
    }
publicstatict unbox(映射数据、字符串键、类类型){
if(data!=null&&data.containsKey(键)){
返回(类型)数据。获取(键);
}
返回null;
}
但这显然不起作用,但从理论上讲,这正是我所期待的解决方案

编辑:以下是复杂类型的示例输入:

// The associatePartyRole is a list of Stings.
@JsonProperty(value = "associatedPartyRole")
public void unboxAssociatedPartyRole(Map<String, Object> data) {
    this.associatedPartyRole = unbox(data, "value", List.class); 

    // Compilation error: Need list, provided object.
}
//associatePartyRole是一个Stings列表。
@JsonProperty(value=“associatedPartyRole”)
公共无效未关联PartyRole(地图数据){
this.associatedPartyRole=unbox(数据,“值”,List.class);
//编译错误:需要列表,提供的对象。
}
编辑2:这是最终的解决方案: PartyDetailsDto.java

public class PartyDetailsDto implements Serializable {
    private static final long serialVersionUID = 3851075484507637508L;

    private String partyId;
    private String partyType;
    private String title;
    private String firstName;
    private String lastName;
    private String middleName;
    private LocalDate dateOfBirth;

    @JsonProperty(value = "partyId")
    public void unboxPartyId(Map<String, String> data) {
        this.partyId = unbox(data, "evidenceId");
    }

    @JsonProperty(value = "partyType")
    public void unboxPartyType(Map<String, String> partyType) {
        this.partyType = unbox(partyType, "value");
    }

    @JsonProperty(value = "individual")
    public void unboxIndividualDetails(Map<String, Object> individual) {
        this.title = unbox(unbox(individual, "title", Map.class), "value");
        this.firstName = unbox(unbox(individual, "firstName", Map.class), "value");
        this.lastName = unbox(unbox(individual, "lastName", Map.class), "value");
        this.middleName = unbox(unbox(individual, "middleName", Map.class), "value");
        this.dateOfBirth = LocalDate.parse(unbox(unbox(individual, "title", Map.class), "value"));
    }
}
public class BaseLineUtil {
    public static <T> T unbox(Map<String, Object> data, String key, Class<?> ofType) {
        return Optional.ofNullable(data)
                .map(m -> (T) ofType.cast(m.get(key)))
                .orElse(null);
    }

    public static <T> T unbox(Map<String, T> data, String key) {
        return Optional.ofNullable(data)
                .map(m -> (T) m.get(key))
                .orElse(null);
    }
}
public类PartyDetailsDto实现可序列化{
私有静态最终长serialVersionUID=3851075484507637508L;
私有字符串partyId;
私有字符串partyType;
私有字符串标题;
私有字符串名;
私有字符串lastName;
私有字符串名称;
私有本地出生日期;
@JsonProperty(value=“partyId”)
public void unexpartyid(地图数据){
this.partyId=unbox(数据,“证据ID”);
}
@JsonProperty(value=“partyType”)
public void unexpartyType(映射partyType){
this.partyType=unbox(partyType,“value”);
}
@JsonProperty(value=“个人”)
public void unboxIndividualDetails(映射个人){
this.title=unbox(unbox(个人,“title”,Map.class),“value”);
this.firstName=unbox(unbox(个人,“firstName”,Map.class),“value”);
this.lastName=unbox(unbox(个人,“lastName”,Map.class),“value”);
this.middleName=unbox(unbox(个人,“middleName”,Map.class),“value”);
this.dateOfBirth=LocalDate.parse(unbox(unbox(个人,“标题”,Map.class),“值”);
}
}
BaseUtil.java

public class PartyDetailsDto implements Serializable {
    private static final long serialVersionUID = 3851075484507637508L;

    private String partyId;
    private String partyType;
    private String title;
    private String firstName;
    private String lastName;
    private String middleName;
    private LocalDate dateOfBirth;

    @JsonProperty(value = "partyId")
    public void unboxPartyId(Map<String, String> data) {
        this.partyId = unbox(data, "evidenceId");
    }

    @JsonProperty(value = "partyType")
    public void unboxPartyType(Map<String, String> partyType) {
        this.partyType = unbox(partyType, "value");
    }

    @JsonProperty(value = "individual")
    public void unboxIndividualDetails(Map<String, Object> individual) {
        this.title = unbox(unbox(individual, "title", Map.class), "value");
        this.firstName = unbox(unbox(individual, "firstName", Map.class), "value");
        this.lastName = unbox(unbox(individual, "lastName", Map.class), "value");
        this.middleName = unbox(unbox(individual, "middleName", Map.class), "value");
        this.dateOfBirth = LocalDate.parse(unbox(unbox(individual, "title", Map.class), "value"));
    }
}
public class BaseLineUtil {
    public static <T> T unbox(Map<String, Object> data, String key, Class<?> ofType) {
        return Optional.ofNullable(data)
                .map(m -> (T) ofType.cast(m.get(key)))
                .orElse(null);
    }

    public static <T> T unbox(Map<String, T> data, String key) {
        return Optional.ofNullable(data)
                .map(m -> (T) m.get(key))
                .orElse(null);
    }
}
public类BaseLineUtil{
公共静态T unbox(映射数据、字符串键、类型类){
返回可选。不可用(数据)
.map(m->type.cast(m.get(key))的(T)
.orElse(空);
}
公共静态T unbox(映射数据、字符串键){
返回可选。不可用(数据)
.map(m->(T)m.get(键))
.orElse(空);
}
}
感谢@deduder@davidxxx的回答。

也许:

public static <T> T unbox(Map<String, T> data, String key) {
    if (data != null && data.containsKey(key)) {
        return data.get(key);
    }
    return null;
}
请注意,您可以简化实现,例如:

public static <T> T unbox(Map<String, T> data, String key) {
  return Optional.ofNullable(data)
                 .map(m -> m.get(key))
                 .orElse(null);
}
通过声明参数化泛型类型方法,编译器从目标类型(接收调用方法返回的变量类型)推断出
T
,因此您可以只执行
return(T)myObject

具体代码:

public static <T> T unboxUnsafe(Map<String, Object> data, String key) {
    return Optional.ofNullable(data)
                   .map(m -> (T)m.get(key))
                   .orElse(null);
}
publicstatict unbxunsafe(映射数据,字符串键){
返回可选。不可用(数据)
.map(m->(T)m.get(键))
.orElse(空);
}
下面是一个样本测试:

public static void main(String[] args) {
    Map<String, Object> mapOfObjects = new HashMap< >( );
    mapOfObjects.put("longKey", 1L );
    mapOfObjects.put("stringKey", "hello" );
    Long l = unboxUnsafe(mapOfObjects, "longKey");
    System.out.println(l);
    String s = unboxUnsafe(mapOfObjects, "stringKey");
    System.out.println(s);
}
publicstaticvoidmain(字符串[]args){
Map mapOfObjects=新HashMap<>();
对象的映射。放置(“长键”,1L);
mapOfObjects.put(“stringKey”,“hello”);
Long l=unbxunsafe(映射对象,“longKey”);
系统输出打印LN(l);
字符串s=unbxunsafe(映射对象,“stringKey”);
系统输出打印项次;
}
输出:

一,

你好

也许:

public static <T> T unbox(Map<String, T> data, String key) {
    if (data != null && data.containsKey(key)) {
        return data.get(key);
    }
    return null;
}
请注意,您可以简化实现,例如:

public static <T> T unbox(Map<String, T> data, String key) {
  return Optional.ofNullable(data)
                 .map(m -> m.get(key))
                 .orElse(null);
}
通过声明参数化泛型类型方法,编译器从目标类型(接收调用方法返回的变量类型)推断出
T
,因此您可以只执行
return(T)myObject

具体代码:

public static <T> T unboxUnsafe(Map<String, Object> data, String key) {
    return Optional.ofNullable(data)
                   .map(m -> (T)m.get(key))
                   .orElse(null);
}
publicstatict unbxunsafe(映射数据,字符串键){
返回可选。不可用(数据)
.map(m->(T)m.get(键))
.orElse(空);
}
下面是一个样本测试:

public static void main(String[] args) {
    Map<String, Object> mapOfObjects = new HashMap< >( );
    mapOfObjects.put("longKey", 1L );
    mapOfObjects.put("stringKey", "hello" );
    Long l = unboxUnsafe(mapOfObjects, "longKey");
    System.out.println(l);
    String s = unboxUnsafe(mapOfObjects, "stringKey");
    System.out.println(s);
}
publicstaticvoidmain(字符串[]args){
Map mapOfObjects=新HashMap<>();
对象的映射。放置(“长键”,1L);
mapOfObjects.put(“stringKey”,“hello”);
Long l=unbxunsafe(映射对象,“longKey”);
系统输出打印LN(l);
字符串s=unbxunsafe(映射对象,“stringKey”);
系统输出打印项次;
}
输出:

一,

你好

·…我采用了[@davidxx]的解决方案,但当返回类型应为列表或数组时,它似乎不起作用。我该怎么处理那个案子?……”

通过我称之为“EDD”的过程,出现了以下处理这些案件的方法

public static < T > T unbox( Map< String, T > data, String key, Class< ? > ofType ) {
    if ( data != null && data.containsKey( key ) ) {
        return (T)ofType.cast( data.get( key ) ) ;
    }
    return null;
}
单击上面链接页面顶部的绿色开始按钮,运行实验



在@saran3h澄清其用例的评论中得到反馈后,以下重构出现在

“我采用了[@davidxx]的解决方案,但当返回类型应该是列表或数组时,它似乎不起作用。我将如何处理这种情况?”

通过我称之为“EDD”的过程,出现了以下处理这些案件的方法

public static < T > T unbox( Map< String, T > data, String key, Class< ? > ofType ) {
    if ( data != null && data.containsKey( key ) ) {
        return (T)ofType.cast( data.get( key ) ) ;
    }
    return null;
}
单击上面链接页面顶部的绿色开始按钮,运行实验



在@saran3h澄清其用例的评论中得到反馈后,以下重构出现在


我更喜欢
returndata==null?null:data.get(key)
而不是创建

...
private static final Map<String, Object> mapOfObjects = new HashMap< >( ); 
...
mapOfObjects.put( foo, (Object)mapOfLists.get( foo ) );
...
BaseUtil user = new BaseUtil( );

user.unboxAssociatedPartyRole( mapOfObjects );

List< Object > objs = user.associatedPartyRole;

assertIsA( objs, List.class );
[What The Reifiable Fuck@&*%$*!?]
                     EXPERIMENT SUCCESSFUL