场景:我正在使用一个不寻常的外部 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"));
}
}
Run Code Online (Sandbox Code Playgroud)
这是示例 util 方法 -unbox我创建它是为了避免编写如此丑陋的代码。现在,它仅适用于返回 String 的情况。
import java.util.Map;
public class BaseUtil {
// TODO: Make this method generic
public static String unbox(Map<String, String> data, String key) {
if (data != null && data.containsKey(key)) {
return data.get(key);
}
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试将上述方法转换为通用方法,我可以在其中动态指定返回类型并相应地转换返回的数据。
谁能帮我创建一个?
我试过这个:
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;
}
Run Code Online (Sandbox Code Playgroud)
但这显然行不通,但理论上这是我所期待的解决方案。
编辑:这是复杂类型的示例输入:
// 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.
}
Run Code Online (Sandbox Code Playgroud)
编辑 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"));
}
}
Run Code Online (Sandbox Code Playgroud)
基础实用程序
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);
}
}
Run Code Online (Sandbox Code Playgroud)
感谢@deduper @davidxxx 的回答。
也许:
public static <T> T unbox(Map<String, T> data, String key) {
if (data != null && data.containsKey(key)) {
return data.get(key);
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
这里T暗示T extends Object.
你可以在任何类中使用它:
Map<String, Integer> map = ...;
Integer value = unbox(map, "key");
Run Code Online (Sandbox Code Playgroud)
请注意,您可以简化您的实现,例如:
public static <T> T unbox(Map<String, T> data, String key) {
return Optional.ofNullable(data)
.map(m -> m.get(key))
.orElse(null);
}
Run Code Online (Sandbox Code Playgroud)
也更高效(单图访问)
OP评论:
我遵循了您的解决方案,但是当返回类型应该是列表或数组时,它似乎不起作用。我将如何处理那个案子
这是令人惊讶的。它应该工作。试试那个示例代码:
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("key", 100);
Integer value = unbox(map, "key");
System.out.println(value);
Map<String, List<Integer>> mapOfList = new HashMap<>();
mapOfList.put("key", Arrays.asList(1, 2));
List<Integer> valueList = unbox(mapOfList, "key");
System.out.println(valueList);
Map<String, int[]> mapOfArray = new HashMap<>();
mapOfArray.put("key", new int[] { 1, 2, 3 });
int[] valueArray = unbox(mapOfArray, "key");
System.out.println(Arrays.toString(valueArray));
}
Run Code Online (Sandbox Code Playgroud)
它输出:
100
[1, 2]
[1, 2, 3]
如果这不是你要找的。请通过准确指定您要执行的操作来重写您的问题。
需求更改后编辑:
public void unboxIndividualDetails(Map<String, Object> individual) {...}
Run Code Online (Sandbox Code Playgroud)
事实上,在这里你想执行不安全的转换。要实现这一点,您不需要传递Class实例,也不会使您的代码类型更安全。
您想要的是告诉编译器接受声明为Object分配给更具体类型变量的对象。
在转换逻辑方面,看起来像:
Object o = Integer.valueOf(100);
Integer i = (Integer)o;
Run Code Online (Sandbox Code Playgroud)
通过声明参数化泛型类型方法,编译器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);
}
Run Code Online (Sandbox Code Playgroud)
这里有一个示例测试:
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);
}
Run Code Online (Sandbox Code Playgroud)
输出 :
1
你好
| 归档时间: |
|
| 查看次数: |
313 次 |
| 最近记录: |