Сериализация Джексона JSON без имени поля

У меня есть JAVA POJO, в котором много полей. Одно из полей - Map<String, Object>, для которого я использую Custom JsonSerializer, так как оно может иметь много типов Objects. Все, что я хочу знать, это как избежать сериализации fieldname только для этого поля Map<String,Object>. Для всех других полей в POJO я хотел бы иметь имя поля, но только для этого я хочу его удалить.

На данный момент, когда я использую поисковик Jackson, я получаю следующий результат:

{
  "isA" : "Human",
  "name" : "Batman",
  "age" : "2008",
  "others" : {
    "key1" : "value1",
    "key2" : {
      "key3" : "value3"
    },
    "key5" : {
      "key4" : "One",
      "key4" : "Two"
    }
  }
}

Я хочу получить следующий результат: (Все, что я хочу сделать, это удалить имя поля Map<String,Object>, но оставить его дочерние элементы.)

{
  "isA" : "Human",
  "name" : "Batman",
  "age" : "2008",
  "key1" : "value1",
  "key2" : {
    "key3" : "value3"
  },
  "key5" : {
    "key4" : "One",
    "key4" : "Two"
  }
}

Ниже приведен мой Human.class POJO, который используется ObjectMapper:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "isA")
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@Getter
@Setter
@NoArgsConstructor
@ToString
class Human {
    private String isA;
    private String name;
    private String age;

    @JsonSerialize(using = MyCustomSearlize.class)
    private Map<String, Object> others = new HashMap<>();
}

Ниже приведен мой Custom searlizer, который используется MAP во время поиска:

class MyCustomSearlize extends JsonSerializer<Map<String, Object>> {

    private static final ObjectMapper mapper = new ObjectMapper();

    @Override
    public void serialize(Map<String, Object> value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeStartObject();
        recusiveSerializer(value, gen, serializers);
        gen.writeEndObject();
    }

    public void recusiveSerializer(Map<String, Object> value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        for (Map.Entry<String, Object> extension : value.entrySet()) {
            if (extension.getValue() instanceof Map) {
                //If instance is MAP then call the recursive method
                gen.writeFieldName(extension.getKey());
                gen.writeStartObject();
                recusiveSerializer((Map) extension.getValue(), gen, serializers);
                gen.writeEndObject();
            } else if (extension.getValue() instanceof String) {
                //If instance is String directly add it to the JSON
                gen.writeStringField(extension.getKey(), (String) extension.getValue());
            } else if (extension.getValue() instanceof ArrayList) {
                //If instance if ArrayList then loop over it and add it to the JSON after calling recursive method
                for (Object dupItems : (ArrayList<Object>) extension.getValue()) {
                    if (dupItems instanceof Map) {
                        gen.writeFieldName(extension.getKey());
                        gen.writeStartObject();
                        recusiveSerializer((Map) dupItems, gen, serializers);
                        gen.writeEndObject();
                    } else {
                        gen.writeStringField(extension.getKey(), (String) dupItems);
                    }
                }
            }
        }
    }
}


Вот мой Main класс:

public class Main {
    public static void main(String[] args) throws JsonProcessingException {

        Human person = new Human();

        person.setName("Batman");
        person.setAge("2008");
        Map<String, Object> others = new HashMap<>();
        others.put("key1", "value1");
        Map<String, Object> complex = new HashMap<>();
        complex.put("key3", "value3");
        others.put("key2", complex);
        Map<String, Object> complex2 = new HashMap<>();
        List<String> dup = new ArrayList<>();
        dup.add("One");
        dup.add("Two");
        complex2.put("key4", dup);
        others.put("key5", complex2);
        person.setOthers(others);

        final ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        objectMapper.registerModule(simpleModule);
        final String jsonEvent = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(person);
        System.out.println(jsonEvent);
    }
}

Следующие вещи, которые я пробовал:

  1. Я попытался добавить @JsonValue на Map, но это удалит все мои другие значения (имя, возраст, isA и т. Д.)
  2. Я пробовал @JsonAnyGetter, это работает для Map и String, но не работает для ArrayList, как я хочу. Я обрабатываю бит ArrayList по-другому в своем приложении, как часть моего требования.

Есть ли способ, чтобы он работал с @JsonSerialize и @JsonAnyGetter, потому что я не могу использовать оба вместе.

Может кто-нибудь помочь в решении этой проблемы? Пожалуйста, помогите мне найти соответствующую документацию или обходной путь, большое спасибо.


person BATMAN_2008    schedule 09.06.2021    source источник


Ответы (2)


На странице вики звучит например, аннотация @JsonUnwrapped должна делать то, что вы хотите.

@JsonUnwrapped: аннотация свойства, используемая для определения этого значения, должна быть развернута при сериализации (и снова упакована при десериализации), что приводит к сглаживанию структуры данных по сравнению со структурой POJO.

Javadoc для class также имеет пример, который выглядит подходящим.

person Hitobat    schedule 09.06.2021
comment
Большое спасибо за ваш быстрый ответ и пример. Я попробовал еще несколько вещей, и все заработало, используя @XmlAnyGetter и @JsonSearlize. - person BATMAN_2008; 09.06.2021
comment
Я приму этот ответ, поскольку вы быстро предоставили несколько полезных документов и примеров. Однако я также опубликую свой ответ, чтобы он мог быть кому-то полезен в будущем. Еще раз спасибо за ответ. Хорошего дня :) - person BATMAN_2008; 09.06.2021

Как упоминалось в другом ответе, @JsonUnwrapped может работать, но я использовал следующий подход, чтобы заставить его работать. Публикация здесь, поскольку это может быть полезно кому-то в будущем:

Я добавил @JsonAnyGetter и @JsonSearlize к Getter методу Map и заставил его работать.

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "isA")
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@Getter
@Setter
@NoArgsConstructor
@ToString
class Human {
    private String isA;
    private String name;
    private String age;

    @JsonIgnore
    private Map<String, Object> others = new HashMap<>();

    @JsonAnyGetter
    @JsonSerialize(using = MyCustomSearlize.class)
    public Map<String,Object> getOther(){
        return others;
    }
}

В коде класса MyCustomSearlize я удалил начальный и конечный объекты

    @Override
    public void serialize(Map<String, Object> value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        recusiveSerializer(value, gen, serializers);
    }
person BATMAN_2008    schedule 09.06.2021