将 POJO 的空字段作为映射中的键 java
Keep null fields of a POJO as keys in map java
我有一个 POJO 并使用对象映射器将其转换为地图。我希望地图在其条目集中包含 POJO 的所有字段,即使它们的值为 null。因此,该条目在我创建的地图中可能为空。
Map<String, Object> oldDetails = objectMapper.convertValue(oldFields, Map.class);
我试过使用下面的代码片段,但这对我没有帮助。
objectMapper.setDefaultPropertyInclusion(JsonInclude.Value.construct(JsonInclude.Include.ALWAYS, JsonInclude.Include.ALWAYS));
还有什么我可以在这里使用的想法吗?
我的 POJO:
@JsonInclude(NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class BaseFields {
@JsonProperty("number") protected String number;
@JsonProperty("name") protected String name;
@JsonProperty("dob") protected String dob;
}
还有其他 类 继承自 BaseFields,例如。
@JsonInclude(NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class CustomerBaseFields extends BaseFields {
@JsonProperty("email") protected String email;
}
现在有一种方法可以将 ChangedBaseFields 的实例转换为映射。
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, true);
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.setDefaultPropertyInclusion(JsonInclude.Value.construct(JsonInclude.Include.ALWAYS, JsonInclude.Include.ALWAYS));
Map<String, Object> oldDetails = objectMapper.convertValue(baseFields, Map.class);
但是如果像电子邮件这样的字段在对象中为空,我的地图中将不会收到关键电子邮件。
下面是简单的代码,证明您的代码实际上可以在没有任何额外配置的情况下使用默认的 ObjectMapper。
package java17test;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;
public class Test {
public static void main(String[] args) {
var objectMapper = new ObjectMapper();
var oldFields = new TestClass();
oldFields.setFirstName("first name");
Map<?, ?> oldDetails = objectMapper.convertValue(oldFields, Map.class);
oldDetails.forEach((key, value) -> System.out.println(key + "=" + value));
}
static class TestClass {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
}
输出:
firstName=first name
lastName=null
您可能有一个 X-Y problem 因为您在对 vbezhenar 的回答的评论中提到您的目的是比较相同类型的两个对象的字段,以找出哪些字段发生了变化。
您不必使用 Jackson 即可。
这是比较两个对象的简单纯 Java(无依赖)方式:
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
public class Utils {
/**
* Compares two objects of the same type, returning the field values that are different.
*
* @param o1 an object
* @param o2 another object
* @return a map of field name to a two-element array of the two different values of o1 and o2
*/
public static <T> Map<String, Object[]> comparePojos(T o1, T o2) throws IllegalAccessException {
Map<String, Object[]> diffs = new LinkedHashMap<>();
for (Field field : o1.getClass().getDeclaredFields()) {
field.setAccessible(true);
Object[] values = {field.get(o1), field.get(o2)};
if (!values[0].equals(values[1]))
diffs.put(field.getName(), values);
}
return diffs;
}
}
class UtilsDemo {
public static void main(String[] args) throws IllegalAccessException {
SamplePojo a = new SamplePojo("alice", 42);
SamplePojo b = new SamplePojo("bob", 42);
Utils.comparePojos(a, b).forEach((k, v) -> System.out.println(k + ": " + Arrays.toString(v)));
}
}
class SamplePojo {
public SamplePojo(String name, int age) {
this.name = name;
this.age = age;
}
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
我有一个 POJO 并使用对象映射器将其转换为地图。我希望地图在其条目集中包含 POJO 的所有字段,即使它们的值为 null。因此,该条目在我创建的地图中可能为空。
Map<String, Object> oldDetails = objectMapper.convertValue(oldFields, Map.class);
我试过使用下面的代码片段,但这对我没有帮助。
objectMapper.setDefaultPropertyInclusion(JsonInclude.Value.construct(JsonInclude.Include.ALWAYS, JsonInclude.Include.ALWAYS));
还有什么我可以在这里使用的想法吗?
我的 POJO:
@JsonInclude(NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class BaseFields {
@JsonProperty("number") protected String number;
@JsonProperty("name") protected String name;
@JsonProperty("dob") protected String dob;
}
还有其他 类 继承自 BaseFields,例如。
@JsonInclude(NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class CustomerBaseFields extends BaseFields {
@JsonProperty("email") protected String email;
}
现在有一种方法可以将 ChangedBaseFields 的实例转换为映射。
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, true);
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.setDefaultPropertyInclusion(JsonInclude.Value.construct(JsonInclude.Include.ALWAYS, JsonInclude.Include.ALWAYS));
Map<String, Object> oldDetails = objectMapper.convertValue(baseFields, Map.class);
但是如果像电子邮件这样的字段在对象中为空,我的地图中将不会收到关键电子邮件。
下面是简单的代码,证明您的代码实际上可以在没有任何额外配置的情况下使用默认的 ObjectMapper。
package java17test;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;
public class Test {
public static void main(String[] args) {
var objectMapper = new ObjectMapper();
var oldFields = new TestClass();
oldFields.setFirstName("first name");
Map<?, ?> oldDetails = objectMapper.convertValue(oldFields, Map.class);
oldDetails.forEach((key, value) -> System.out.println(key + "=" + value));
}
static class TestClass {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
}
输出:
firstName=first name
lastName=null
您可能有一个 X-Y problem 因为您在对 vbezhenar 的回答的评论中提到您的目的是比较相同类型的两个对象的字段,以找出哪些字段发生了变化。
您不必使用 Jackson 即可。
这是比较两个对象的简单纯 Java(无依赖)方式:
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
public class Utils {
/**
* Compares two objects of the same type, returning the field values that are different.
*
* @param o1 an object
* @param o2 another object
* @return a map of field name to a two-element array of the two different values of o1 and o2
*/
public static <T> Map<String, Object[]> comparePojos(T o1, T o2) throws IllegalAccessException {
Map<String, Object[]> diffs = new LinkedHashMap<>();
for (Field field : o1.getClass().getDeclaredFields()) {
field.setAccessible(true);
Object[] values = {field.get(o1), field.get(o2)};
if (!values[0].equals(values[1]))
diffs.put(field.getName(), values);
}
return diffs;
}
}
class UtilsDemo {
public static void main(String[] args) throws IllegalAccessException {
SamplePojo a = new SamplePojo("alice", 42);
SamplePojo b = new SamplePojo("bob", 42);
Utils.comparePojos(a, b).forEach((k, v) -> System.out.println(k + ": " + Arrays.toString(v)));
}
}
class SamplePojo {
public SamplePojo(String name, int age) {
this.name = name;
this.age = age;
}
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}