У меня есть POJO и я использую средство сопоставления объектов, чтобы преобразовать его в карту. Я хочу, чтобы карта содержала все поля POJO в своем наборе записей, даже если их значение равно нулю. Так что эта запись может быть нулевой на карте, которую я создаю.

Map<String, Object> oldDetails = objectMapper.convertValue(oldFields, Map.class);

Я пробовал использовать приведенный ниже фрагмент, но это мне не помогло.

objectMapper.setDefaultPropertyInclusion(JsonInclude.Value.construct(JsonInclude.Include.ALWAYS, JsonInclude.Include.ALWAYS));

Любая другая идея, которую я могу использовать здесь?

МОЙ ПОЖО:

@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);

Но скажем, если поле, такое как электронная почта, имеет значение null в объекте, я не получаю ключевое электронное письмо на своей карте.

0
N.Rajal 4 Фев 2022 в 13:35
И что случилось с этим фрагментом? На карте отсутствуют нулевые поля. Возникло исключение NullPointertException? Просьба уточнить.
 – 
Alex Rudenko
4 Фев 2022 в 13:43
Пустые поля отсутствуют на карте. Только ненулевые поля являются частью карты.
 – 
N.Rajal
4 Фев 2022 в 13:44
Я не могу воспроизвести проблему. Это работает нормально. Можете ли вы написать автономный минимальный исполняемый файл?
 – 
k314159
4 Фев 2022 в 13:58
Обновлены некоторые фрагменты кода, пожалуйста, проверьте. @k314159
 – 
N.Rajal
4 Фев 2022 в 14:23

2 ответа

Вот простой код, демонстрирующий, что ваш код действительно работает без дополнительной настройки с 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
1
vbezhenar 4 Фев 2022 в 14:03
Я только что понял, что javing @JsonIgnore(NON_NULL) может вызывать здесь проблему.
 – 
N.Rajal
4 Фев 2022 в 14:26
Мое первоначальное намерение состояло в том, чтобы сравнить и получить различия между двумя объектами. Как будто мне нужно было знать, какие поля обновляются в новом pojo.
 – 
N.Rajal
4 Фев 2022 в 14:26
Есть ли способ переопределить свойство @JsonIgnore с помощью objectmapper?
 – 
N.Rajal
4 Фев 2022 в 14:30
@N.Rajal Вы можете настроить свой картограф с помощью MapperFeature.USE_ANNOTATIONS, false, но в этом случае он будет игнорировать все аннотации, которые могут вам подойти или нет. Я не думаю, что вы можете выборочно отключить определенную аннотацию.
 – 
vbezhenar
4 Фев 2022 в 14:34
Спасибо @vbezhenar. Я попробовал свойство USE_ANNOTATION, вроде работает нормально. Однако во всех преобразованных картах добавлен логический элемент, называемый пустым (как ложный). Хотя это не должно быть проблемой, но это поле по умолчанию или мы можем удалить и его?
 – 
N.Rajal
4 Фев 2022 в 15:14

У вас, вероятно, есть проблема XY, потому что вы упомянули в комментарии к ответу vbezhenar, что вы намерены сравнить поля двух объектов одного типа, чтобы узнать, какие поля изменились.

Вам не нужно использовать Джексона для этого.

Вот простой чистый 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;
    }
}
0
k314159 4 Фев 2022 в 15:07