使用API,我收到如下JSON (这些JSON现在保存到文件中):
[{
"LEI": {
"$": "549300Q82NZ9NYNMZT63"
},
"Entity": {
"LegalName": {
"$": "United Nerds in Collaboration of Random Nerdiness AB"
},
"LegalAddress": {
"Line1": {
"$": "BOX 155"
},
"City": {
"$": "Alingsas"
},
"Region": {
"$": "SE-O"
},
"Country": {
"$": "SE"
},
"PostalCode": {
"$": "44123"
}
},
"HeadquartersAddress": {
"Line1": {
"$": "BOX 155"
},
"City": {
"$": "Alingsas"
},
"Region": {
"$": "SE-O"
},
"Country": {
"$": "SE"
},
"PostalCode": {
"$": "44123"
}
},
"BusinessRegisterEntityID": {
"@register": "SE001",
"$": "5568557184"
},
"LegalJurisdiction": {
"$": "SE"
},
"LegalForm": {
"$": "PRIVATA AKTIEBOLAG"
},
"EntityStatus": {
"$": "ACTIVE"
}
},
"Registration": {
"InitialRegistrationDate": {
"$": "2016-06-23T01:48:45.025Z"
},
"LastUpdateDate": {
"$": "2016-06-23T01:48:44.945Z"
},
"RegistrationStatus": {
"$": "ISSUED"
},
"NextRenewalDate": {
"$": "2017-06-21T06:32:03.821Z"
},
"ManagingLOU": {
"$": "EVK05KS7XY1DEII3R011"
},
"ValidationSources": {
"$": "PARTIALLY_CORROBORATED"
}
}
}]我想把Java对象从这些东西中拿出来。我已经从提供的xsd文件中创建了Java对象。我正在运行的代码是:
public static void toJava() {
ObjectMapper mapper = new ObjectMapper();
try {
File json = new File("C:\\temp\\JSON.json");
LEIRecordType[] type = mapper.readValue(json, LEIRecordType[].class);
} catch (JsonEOFException ex) {
ex.printStackTrace();
} catch (JsonMappingException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
}它创建了以下异常:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "LEI" (class org.leiroc.data.schema.leidata._2014.LEIRecordType), not marked as ignorable (5 known properties: "lei", "registration", "entity", "nextVersion", "extension"])
at [Source: (File); line: 3, column: 14] (through reference chain: java.lang.Object[][0]->org.leiroc.data.schema.leidata._2014.LEIRecordType["LEI"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:60)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:822)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1152)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1567)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1545)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:293)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:195)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:21)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2890)
at Test.JSONParser.toJava(JSONParser.java:38)
at Test.JSONParser.main(JSONParser.java:29)LEIRecordType看起来是这样的:
package org.leiroc.data.schema.leidata._2014;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "LEIRecordType", propOrder = {"lei", "entity", "registration", "nextVersion", "extension"})
public class LEIRecordType {
@XmlElement(name = "LEI", required = true)
protected String lei;
@XmlElement(name = "Entity", required = true)
protected EntityType entity;
@XmlElement(name = "Registration", required = true)
protected RegistrationType registration;
@XmlElement(name = "NextVersion")
protected LEIRecordNextVersionType nextVersion;
@XmlElement(name = "Extension")
protected ExtensionType extension;
public String getLEI() {
return this.lei;
}
public void setLEI(String paramString) {
this.lei = paramString;
}
public EntityType getEntity() {
return this.entity;
}
public void setEntity(EntityType paramEntityType) {
this.entity = paramEntityType;
}
public RegistrationType getRegistration() {
return this.registration;
}
public void setRegistration(RegistrationType paramRegistrationType) {
this.registration = paramRegistrationType;
}
public LEIRecordNextVersionType getNextVersion() {
return this.nextVersion;
}
public void setNextVersion(LEIRecordNextVersionType paramLEIRecordNextVersionType) {
this.nextVersion = paramLEIRecordNextVersionType;
}
public ExtensionType getExtension() {
return this.extension;
}
public void setExtension(ExtensionType paramExtensionType) {
this.extension = paramExtensionType;
}
}我了解到问题在于jackson正在锁定一个名为LEI的Java对象,并使用一个名为"$“的变量。但根本就没有。这些组织的帮助服务机构说:
"$“对象总是复制相应XML元素的简单内容(即不是属性、子节点等)。如果适用,"$”对象应该始终作为JSON字符串类型。
但据我所知,这不是JSON标准。
我的问题是:有没有办法让杰克逊解析为LEI =“549300Q82NZ9NYNMZT 63”等,而不是用变量"$“来对象LEI?在一天的大部分时间里都被困在这上面。
@UPDATE这种JSON格式显然被称为“BadgerFish约定”,根据客户服务。
发布于 2017-12-12 18:02:32
由于$对象始终是String,因此可以为处理BadgerFish包装对象的String创建自定义反序列化器。
这个反序列化器检查在一个BadgerFish值周围是否有一个String包装器对象,并对它进行解压缩。正常的String值会像往常一样反序列化。
public class BadgerFishDeserializer extends StdDeserializer<String> {
private static final long serialVersionUID = 1L;
private static final SerializedString BADGER_FISH_FIELD_NAME = new SerializedString("$");
public BadgerFishDeserializer() {
super(String.class);
}
@Override
public String deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
// do we have a wrapper object?
if (jp.isExpectedStartObjectToken()) {
// check if first field name is equal to '$'
if (!jp.nextFieldName(BADGER_FISH_FIELD_NAME)) {
ctxt.reportInputMismatch(String.class, "Expected BadgerFish field name '$', but got '%s'", jp.getCurrentName());
}
jp.nextValue(); // proceed to the actual value
String value = jp.getValueAsString(); // read value as string
jp.nextToken(); // consume END_OBJECT of wrapper object
return value;
}
// else: just return string value
return jp.getValueAsString();
}
}最后,在Jackson ObjectMapper实例上注册该模块:
SimpleModule module = new SimpleModule();
module.addDeserializer(String.class, new BadgerFishDeserializer());
mapper.registerModule(module);注释:--如果您只想打开一些属性,可以创建一个自定义注释,并使用BeanDeserializerModifier检查注释,然后提供一个反序列化器来处理包装器对象。
一些值得思考的东西:
DeserializerModifierDeserializerModifier上注册ObjectMapper困难的部分:
public class BadgerFishDeserializerModifier extends BeanDeserializerModifier {
@Override
public BeanDeserializerBuilder updateBuilder(DeserializationConfig config, BeanDescription beanDesc, BeanDeserializerBuilder builder) {
Iterator<SettableBeanProperty> props = builder.getProperties();
while (props.hasNext()) {
SettableBeanProperty prop = props.next();
if (prop.getAnnotation(MyAnnotation.class) != null) {
builder.addOrReplaceProperty(prop.withValueDeserializer(new BadgerFishDeserializer()), true);
}
}
return builder;
}
}发布于 2017-12-19 14:08:37
这是非常有用的!最后,我不得不为String和XMLGregorianCalendar做一个特殊的反序列化器。但问题并不止步于此。BadgerFish从生成的类中获取@XMLAttributes,并将它们设置为@value,而不是"value“。例如:
"BusinessRegisterEntityID": {
"@register": "SE001",
"$": "5568557184"
}那么,他们有没有办法也自定义字段名回到原名?目前,我得到了这个例外:
Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "@register" (class leigen.BusinessRegisterEntityIDType), not marked as ignorable (2 known properties: "value", "register"])
at [Source: (File); line: 44, column: 27] (through reference chain: java.lang.Object[][0]->leigen.LEIRecordType["Entity"]->leigen.EntityType["BusinessRegisterEntityID"]->leigen.BusinessRegisterEntityIDType["@register"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:60)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:822)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1152)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1567)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1545)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:293)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:136)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:287)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:136)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:287)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:195)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:21)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2890)
at Test.JSONParser.toJava(JSONParser.java:47)
at Test.JSONParser.main(JSONParser.java:28)我可以通过在配置中添加一个“忽略”(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES来绕过这一点,就像我现在的代码中一样:
public static LEIRecordType[] toJava(File json) throws JsonParseException, JsonMappingException, IOException {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(String.class, new BadgerFishStringDeserializer());
module.addDeserializer(XMLGregorianCalendar.class, new BadgerFishXMLGregorianCalendarDeserializer());
module.addDeserializer(NameType.class, new BadgerFishNameTypeDeserializer());
mapper.registerModule(module);
mapper.registerModule(new JaxbAnnotationModule()); // To be able to read JAXB annotations.
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return mapper.readValue(json, LEIRecordType[].class);
} 但这只设置以@ as null开头的值。还有别的办法解决这个问题吗?否则,我将不得不为所有生成的类编写一个自定义反序列化器,这大约是25个(下一个版本中可能会有更多的类)。我已经为NameType做了一个,但对于其他例子,还需要更多。
发布于 2020-01-10 09:36:27
我认为明确的解决方案是使用@JsonProperty("$"):
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
List<LEIModel> leiList = Arrays.asList(mapper.readValue(response.toString(), LEIModel[].class));LEIModel类:
public class LEIModel {
@JsonProperty("Entity")
private Entity entity;
public Entity getEntity() {
return entity;
}
public void setEntity(Entity entity) {
this.entity = entity;
}
}实体类:
public class Entity {
@JsonProperty("LegalName")
private LegalName legalName;
public LegalName getLegalName() {
return legalName;
}
public void setLegalName(LegalName legalName) {
this.legalName = legalName;
}
}LegalName类:
public class LegalName {
@JsonProperty("$")
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}https://stackoverflow.com/questions/47775427
复制相似问题