Как я могу десериализовать строку Json, где подкласс класса объекта включен в строку json, используя библиотеку Java и Jackson

Я очень новичок в Java. У меня есть несколько классов Site, Instances, CloudInstance. Класс Site имеет экземпляры атрибутов, а класс CloudInstance наследует класс Instance. Они как follows-

public class Site extends BaseEntity { private String siteName; List<instance> instances = Lists.newArrayList(); } public class Instance extends BaseEntity { private String instanceId; private String name; } public class CloudInstance extends Instance { private String availabilityZone; private String instanceType }
</instance>

Я десериализую строку json следующим образом -

import com.fasterxml.jackson.databind.ObjectMapper; ObjectMapper mapper = new ObjectMapper(); BaseEntity obj = null; obj = (BaseEntity) mapper.readValue(jsonStr, Site.class);

Он отлично работает, если мой jsonStr не содержит полей класса "CloudInstance" и содержит экземпляр поля с полями класса экземпляров.

Проблема. Теперь я хочу десериализовать jsonStr, который включает в себя "CloudInstance" classe fiels, а также часть поля "экземпляров" класса "Сайт". Ex jsonStr выглядит следующим образом:

{ "id": null, "siteName": "demo", "instances": [ { "instanceId": "i-8c2ee5fc", "name": "some-node", "availabilityZone": "some-zone", "instanceType": "t1.micro" }] }

Для вышеупомянутого jsonStr я получаю следующую ошибку

error: Unrecognized field \"availabilityZone\" and error: Unrecognized field \"instanceType\"

С большим количеством, если еще и грязным кодом, я могу получить объект сайта, включая вышеуказанные поля. Но я хочу реализовать для этого чистое решение. Есть ли библиотека, которая может это сделать? Любая помощь id является ценной. Пожалуйста помоги..!!

Заранее спасибо.

4 ответа

То, что вы пытаетесь достичь, называется полиморфной десериализацией. Ваш пример терпит неудачу, потому что Джексону необходимо знать, какой тип экземпляра должен быть построен из JSON и помещен в список экземпляров. Пожалуйста, обратитесь к этой вики-странице для подробного объяснения.

Я сделал вам пример, чтобы продемонстрировать, как он может работать. Я добавил информацию о типе экземпляра в поле @type в представлении JSON. Также я сделал все классы неизменными, используя конструкторы, аннотированные аннотацией @JsonCreator, для создания экземпляров.

public class JacksonPolymorphism { public static class BaseEntity { private final String id; protected BaseEntity(String id) { this.id = id; } } public static class Site extends BaseEntity { private final String siteName; private final List<instance> instances; @JsonCreator public Site(@JsonProperty("id") String id, @JsonProperty("siteName") String siteName, @JsonProperty("instances") List<instance> instances) { super(id); this.siteName = siteName; this.instances = instances; } @Override public String toString() { return "Site{" + "siteName='" + siteName + '\'' + ", instances=" + instances + '}'; } } @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "@type") @JsonTypeName(value = "simple") public static class Instance extends BaseEntity { private final String name; @JsonCreator public Instance(@JsonProperty("instanceId") String id, @JsonProperty("name") String name) { super(id); this.name = name; } @Override public String toString() { return "Instance{" + "name='" + name + '\'' + '}'; } } @JsonTypeName("cloud") public static class CloudInstance extends Instance { private final String availabilityZone; private final String instanceType; public CloudInstance(@JsonProperty("instanceId") String id, @JsonProperty("name") String name, @JsonProperty("availabilityZone") String availabilityZone, @JsonProperty("instanceType") String instanceType) { super(id, name); this.availabilityZone = availabilityZone; this.instanceType = instanceType; } @Override public String toString() { return "CloudInstance{" + "availabilityZone='" + availabilityZone + '\'' + ", instanceType='" + instanceType + '\'' + '}'; } } public static final String JSON = "{\n" + " \"id\": null,\n" + " \"siteName\": \"demo\",\n" + " \"instances\": [\n" + " {\n" + " \"@type\": \"cloud\",\n" + " \"instanceId\": \"i-8c2ee5fc\",\n" + " \"name\": \"some-node\",\n" + " \"availabilityZone\": \"some-zone\",\n" + " \"instanceType\": \"t1.micro\" \n" + " }," + " {\n" + " \"@type\": \"simple\",\n" + " \"instanceId\": \"ABC\",\n" + " \"name\": \"FGF\"\n" + " }]" + " }"; public static void main(String[] args) throws IOException { ObjectMapper mapper = new ObjectMapper(); mapper.registerSubtypes(CloudInstance.class); System.out.println(mapper.readValue(JSON, Site.class)); }
}
</instance></instance>

Вывод:

Site{siteName='demo', instances=[CloudInstance{availabilityZone='some-zone', instanceType='t1.micro'}, Instance{name='FGF'}]}


Вы можете использовать библиотеку GSON для де-сериализации Json в свой объект класса.

Существует функция gson.fromJson(JSON String) которая преобразует строку json в объект класса.

Вот пример кода:

Gson json = new Gson();
Site site = json.fromJson(jsonStr, Site.class);

Но в вашем коде вы замените

List<instance> instances = Lists.newArrayList();
</instance>

эта строка в классе Site with

List<cloudinstance> instances = new ArrayList<cloudinstance>();
</cloudinstance></cloudinstance>

Поскольку ваш класс CloudInstance расширяет Instance это означает, CloudInstance класс CloudInstance включает член класса Instance. В соответствии с json вам нужно сделать это, чтобы напрямую вставить объект класса.

Пусть это поможет вам.


У меня всегда были проблемы для десериализации JSON, который содержит объекты List <...> с Jackson, поэтому попробуйте десериализовать с Gson:

https://code.google.com/p/google-gson/

Взгляните на документацию по методам fromJson и toJson.

Надеюсь, это может помочь, С наилучшими пожеланиями


Никогда не было постоянной удачи с Джексоном или Гсоном, вместо этого попробуйте использовать Flex JSON:

JSONSerializer ser = new JSONSerializer(); String json = ser.deepSerialize(yourObject); JSONDeserializer<yourmaintype> der = new JSONDeserializer<yourmaintype>(); YourMainType mainType = der.deserialize(json);
</yourmaintype></yourmaintype>

Чтобы это работало, все классы, подверженные сериализации/десериализации, должны выставлять геттеры/сеттеры в соответствии с соглашением Java Beans.

licensed under cc by-sa 3.0 with attribution.