Проанализируйте неявный список JSON, заданный ключами «1», «2»

#java #json #jackson

Вопрос:

Я получаю этот JSON от API.

 {
    "message" : "message",
    "1": {
        "packageCode": "packageCode1",
        "packageNum": "packageNum1"
    },
    "2": {
        "packageCode": "packageCode2",
        "packageNum": "packageNum2"
    }
}
 

Можно ли преобразовать его в объект java со следующими атрибутами?

  • Строковое сообщение
  • Пакет [] пакеты

Я использую jackson-databind ObjectMapper .

Спасибо!

Комментарии:

1. Контролируете ли вы API? Возврат ключей, которые на самом деле являются значениями, а не предопределенными статическими ключами, на самом деле не является хорошим дизайном-поэтому у вас теперь возникают проблемы с его чтением.

2. Действительно ли цифры начинаются с 1 ? Вы хотите пропустить элемент 0 массива? Если да, то что происходит в этом месте — null ?

3. Привет, да, я знаю, что это не очень хороший дизайн, но это сторонний API. Я не могу это контролировать. Цифры действительно начинаются с 1, и у меня тоже не может быть предметов

4. Можете ли вы добавить код, чтобы показать, что вы пробовали ?

5. Я добавил рабочее решение

Ответ №1:

Лучше изменить API, который возвращает этот JSON, чтобы возвращать массив пакетов.

 {
    "message" : "message",
    "packages": [
    {
        "packageCode": "packageCode1",
        "packageNum": "packageNum1"
    },
    {
        "packageCode": "packageCode2",
        "packageNum": "packageNum2"
    }]
}
 

Если это невозможно изменить, вам нужно будет написать пользовательский десереализатор, расширив StdDeserializer<T> класс. Вам придется программно проверить JsonNode дерево синтаксического анализа и собрать нужный объект.

В этой статье объясняется, как это сделать, и приводится пример рабочего кода.

Комментарии:

1. К сожалению, я не могу изменить API.

2. Затем вам придется сделать пользовательский десериализатор 🙁

3. хорошо, я использовал его, и он работает! Спасибо вам за ваш ответ. Я вставил рабочий раствор

4. Если это помогло вам, пожалуйста, отметьте это как принятый ответ зеленой галочкой. Спасибо.

5. хорошо, вы тоже можете проверить полный код. Я написал это, используя предложенный вами учебник

Ответ №2:

Я нашел это рабочее решение, используя пользовательский десериализатор! Я определил максимальное количество разрешенных пакетов, но эта проверка может быть удалена, если в этом нет необходимости.

Ответ класса:

 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

    @Getter
    @Setter
    @ToString
    @JsonDeserialize(using = ResponseDeserializer.class)
    public class Response {
    
        private String message;
        private Package [] packages;
    }
 

Пакет классов:

 import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class Package {

    private String packageCode;
    private String packageNum;
}
 

Класс ResponseDeserializer:

 import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;

public class ResponseDeserializer extends StdDeserializer<Response> {

    private static final long serialVersionUID = -6665611685508708642L;
    private static final long MAX_PACKAGE_NUM = 1000;
    private ObjectMapper objectMapper = new ObjectMapper();

    public ResponseDeserializer() {
        this(null);
    }

    public ResponseDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public Response deserialize(JsonParser parser, DeserializationContext ctx)
            throws IOException {
        final JsonNode node = parser.getCodec().readTree(parser);
        final String message = node.get("message").asText();
        final List<Package> packageList = new ArrayList<>();
        for (var key = 1; key < MAX_PACKAGE_NUM; key  ) {
            var packageNode = node.get(String.valueOf(key));
            if (null == packageNode) {
                break;
            }
            var currentPackage = objectMapper.treeToValue(packageNode, Package.class);
            packageList.add(currentPackage);
        }
        final var response = new Response();
        response.setMessage(message);
        response.setPackages(packageList.toArray(new Package[0]));
        return response;
    }
}
 

Тестовый сериализатор класса (образец):

 import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class TestDeserializer {

    public static void main(String[] args) throws JsonMappingException, JsonProcessingException {
        String responseJSON = """
                                {
                    "message" : "message",
                    "1": {
                        "packageCode": "packageCode1",
                        "packageNum": "packageNum1"
                    },
                    "2": {
                        "packageCode": "packageCode2",
                        "packageNum": "packageNum2"
                    }
                }

                                """;
        Response response = new ObjectMapper().readValue(responseJSON, Response.class);
        System.out.println(response.toString());

    }
}
 

Ответ №3:

Удалось решить проблему с помощью пользовательского десериализатора.

 package com.test.json;

import java.io.IOException;
import java.util.ArrayList;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;

public class TestJsonObjectDeserializer extends StdDeserializer<TestJsonObject> {

    private static final long serialVersionUID = 1L;

    public TestJsonObjectDeserializer() {
        this(null);
    }

    protected TestJsonObjectDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public TestJsonObject deserialize(JsonParser jsonParser, DeserializationContext arg1) throws IOException, JsonProcessingException {
        TestJsonObject testJsonObject = new TestJsonObject();
        JsonNode jsonNode = jsonParser.getCodec().readTree(jsonParser);
        String message = jsonNode.get("message").textValue();
        ArrayList<Package> packages = new ArrayList<Package>();
        if (message != null) {
            testJsonObject.setMessage(message);
            int i = 1;
            Package package1 = null;
            do {
                package1 = null;
                JsonNode pkg = null;
                if (jsonNode.get(String.valueOf(i)) != null) {
                    pkg = jsonNode.get(String.valueOf(i));
                    String packageCode = pkg.get("packageCode").textValue();
                    String packageNum = pkg.get("packageNum").textValue();
                    package1 = new Package();
                    package1.setPackageCode(packageCode);
                    package1.setPackageNum(packageNum);
                }
                i  ;
                if (package1 != null) {
                    packages.add(package1);
                }
            } while (package1 != null);

            if (!packages.isEmpty()) {
                Package[] packages1 = new Package[packages.size()];
                testJsonObject.setPackages(packages.toArray(packages1));
            }
            return testJsonObject;
        }
        return null;
    }

}
 

вот объекты:
Package.java

 package com.test.json;

public class Package {
    protected String packageCode;
    protected String packageNum;

    public String getPackageCode() {
        return packageCode;
    }

    public void setPackageCode(String packageCode) {
        this.packageCode = packageCode;
    }

    public String getPackageNum() {
        return packageNum;
    }

    public void setPackageNum(String packageNum) {
        this.packageNum = packageNum;
    }

    @Override
    public String toString() {
        return "Package [packageCode="   packageCode   ", packageNum="   packageNum   "]";
    }
}
 

TestJsonObject:

 package com.test.json;

import java.util.Arrays;

public class TestJsonObject {
    protected String message;
    protected Package[] packages;

    public String getMessage() {
        return message;
    }

    @Override
    public String toString() {
        return "TestJsonObject [message="   message   ", packages="   Arrays.toString(packages)   "]";
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Package[] getPackages() {
        return packages;
    }

    public void setPackages(Package[] packages) {
        this.packages = packages;
    }
}