Map Java Object to #XmlElement Value - java

The LocationType Set coming null when I'm running JAXBxmlToJava. Can any body suggest how to map type component of xml to LocationType Object of Java.
I have following arc-response.xml:-
<address_component>
<long_name>BMC Colony</long_name>
<short_name>BMC Colony</short_name>
<type>neighborhood</type>
<type>political</type>
</address_component>
And Following Code, AddressComponent:-
#XmlRootElement(name = "address_component")
public class AddressComponent {
#XmlElement(name = "long_name")
private String longName;
#XmlElement(name = "short_name")
private String shortName;
#XmlElement(name = "type")
private Set<LocationType> locationTypeSet;
//Setter Getter
}
LocationType:-
#XmlRootElement(name="type")
public class LocationType {
private Integer locationTypeId;
#XmlElement(name = "type")
private String type;
private String status;
//Setter Getter
}
JAXBxmlToJava.java:-
public class JAXBxmlToJava {
public static void main(String[] args) {
try {
File file = new File("arc-response.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(AddressComponent.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
AddressComponent geoResponse = (AddressComponent) jaxbUnmarshaller.unmarshal(file);
System.out.println(geoResponse);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}

You'll need #XmlValue to map a text node (e.g. 'neighborhood') to a field in a custom class.
When I tested your code, the Set<LocationType> wasn't null - there were two LocationTypes in it, but their type field was null. I'm not sure if that is what you meant in your question.
When I changed the LocationType class to
#XmlRootElement(name = "type")
public class LocationType {
private Integer locationTypeId;
#XmlValue
private String type;
private String status;
// Setter Getter
}
it worked.

Related

Unexpected token (FIELD_NAME), expected END_OBJECT: expected closing END_OBJECT after type information and deserialized value

I have my API which takes a FileImportInput and this has the following model
FileImportInput {
private String importType;
private String resourceUri;
#JsonProperty("settings")
private MriImportRequest settings;
}
This MriImportRequest is the base class with the following fields
#JsonTypeInfo(use = Id.NAME, include = As.WRAPPER_OBJECT, property = "settings")
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonSubTypes({
#JsonSubTypes.Type(value = MriExcelImportRequest.class, name = "sheets"),
#JsonSubTypes.Type(value = MriTextFileImportRequest.class, name = "files")
})
public class MriImportRequest {
private int folderId;
private String locale;
private String currency;
}
Below are other two classes with the following definitions.
#JsonTypeName("files")
public class MriTextFileImportRequest extends MriImportRequest {
private int accountsFileId;
private int locationsFileId;
private int reinsuranceFileId;
private int mappingFileId;
}
The other class is as follows
#JsonTypeName("sheets")
public class MriExcelImportRequest extends MriImportRequest {
private int accountsSheetIndex;
private int locationsSheetIndex;
private int reinsuranceSheetIndex;
private int mappingFileIndex;}
The request JSON is below, When i make a request, Unrecognized field "files" I am not sure whats missing. The request Json is below
{
"importType": "mri",
"resourceUri": "riskdata/v1/exposuresets/es1/exposures/sdfd-2232-skdj-3434/portfolios/12",
"settings": {
"files": {
"accountsFileId": 5387,
"locationsFileId": 5388,
"reinsuranceFileId": 5389,
"mappingFileId": 5390
},
"folderId": 1686,
"currency": "USD",
"locale": "US"
}
}
The JsonTypeInfo.As#WRAPPER_OBJECT is used for serialization while you are trying to deserialize your json, so no use for it in this case. Instead you can use the JsonTypeInfo.Id#DEDUCTION to deduce types based on the fields available (in this case if files property is available the value will be automatically deserialized to the MriTextFileImportRequest subclass:
#Data
public class FileImportInput {
private String importType;
private String resourceUri;
#JsonProperty("settings")
private MriImportRequest settings;
}
#Data
#JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
#JsonSubTypes({
#JsonSubTypes.Type(value = MriTextFileImportRequest.class)
})
public class MriImportRequest {
private int folderId;
private String locale;
private String currency;
}
#Data
public class MriTextFileImportRequest extends MriImportRequest {
private Files files;
}
#Data
public class Files {
private int accountsFileId;
private int locationsFileId;
private int reinsuranceFileId;
private int mappingFileId;
}
Then the code below prints the json input file:
FileImportInput fileImportInput = mapper.readValue(json, FileImportInput.class);
//ok it prints the input json file
System.out.println(mapper.writeValueAsString(fileImportInput));

Map String to Object using Jackson with inheritance

I have the QueueContent class that it has is a superclass of two others.
I get a String in JSON format that contains the information I need to extract. The super class is:
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class QueueContent {
private String empresa;
private String empresa_cor;
private String empresa_contato;
private String empresa_url;
private String empresa_telefone;
private String empresa_idioma;
public QueueContent(String empresa, String empresa_cor, String empresa_contato, String empresa_url, String empresa_telefone, String empresa_idioma) {
this.empresa = empresa;
this.empresa_cor = empresa_cor;
this.empresa_contato = empresa_contato;
this.empresa_url = empresa_url;
this.empresa_telefone = empresa_telefone;
this.empresa_idioma = empresa_idioma;
}
public QueueContent() {
}
}
I'm using Lombok to generate Getters / Setters)
This is the child class:
#Data
public class EmailCameraOffline extends QueueContent {
private Timestamp camera_last_online;
private String camera_nome;
private String empresa_url_plataforma;
public EmailCameraOffline(String empresa, String empresa_cor, String empresa_contato, String empresa_url, String empresa_telefone, String empresa_idioma, Timestamp camera_last_online, String camera_nome, String empresa_url_plataforma) {
super(empresa, empresa_cor, empresa_contato, empresa_url, empresa_telefone, empresa_idioma);
this.camera_last_online = camera_last_online;
this.camera_nome = camera_nome;
this.empresa_url_plataforma = empresa_url_plataforma;
}
public EmailCameraOffline() {
}
}
So I've done:
EmailCameraOffline infosEmail = new ObjectMapper().readValue(content, EmailCameraOffline.class);
System.out.println(infosEmail);
And the output is:
EmailCameraOffline (camera_last_online = 2020-03-12 03: 01: 45.0, camera_nome = Pier Cam 1, empresa_url_platform = null)
How do I get my EmailCameraOffline object to have the superclass attributes initialized?
Everything should be loaded and initialized just fine, so calling:
System.out.println(infosEmail.getEmpresa());
should give expected value.
Problem
The problem is in the default implementation of toString() method (done via #Data) at EmailCameraOffline class, which does not include inherited fields.
Solution
To fix this you can "override" #Data's toString() implementation to include inherited fields as well using Lombok as:
#Data
#ToString(callSuper = true)
public class EmailCameraOffline extends QueueContent {
...
}

Consuming XML return selected date in order to XMLElements

I am trying to consume api which returns XML.
The api url: api
This is how my XML classes looks:
#XmlRootElement(name="ArrayOfExchangeRatesTable")
#XmlAccessorType(XmlAccessType.FIELD)
public class RootElement {
#XmlElement(name="ExchangeRatesTable")
private TableRateModel tableRateModel;
#XmlAccessorType(XmlAccessType.FIELD)
public class TableRateModel {
#XmlElement(name="Table")
private String table;
#XmlElement(name="EffectiveDate")
private Date effectiveDate;
#XmlElement(name="Rates")
private List<RateModel> rates;
#XmlAccessorType(XmlAccessType.FIELD)
public class RateModel {
#XmlElement(name="Currency")
private Currency currency;
#XmlElement(name="Code")
private String code;
#XmlElement(name="Mid")
private Double mid;
Then in the end I printed it and get a result as:
RootElement{tableRateModel=TableRateModel{table='A', effectiveDate=Thu Jul 20 00:00:00 CEST 2017, rates=[RateModel{currency=null, code='null', mid=null}]}}
Why the list of Rates is null?
The problem is that the XML-elements Rate is wrapped inside a element named Rates. I tested the following classes and got it to work
#XmlRootElement(name = "ArrayOfExchangeRatesTable")
#XmlAccessorType(XmlAccessType.FIELD)
public class RootElement {
#XmlElement(name = "ExchangeRatesTable")
private TableRateModel tableRateModel;
}
#XmlAccessorType(XmlAccessType.FIELD)
class TableRateModel {
#XmlElement(name = "Table")
private String table;
#XmlElement(name = "EffectiveDate")
private Date effectiveDate;
#XmlElement(name = "Rates")
private Rates rates;
}
#XmlAccessorType(XmlAccessType.FIELD)
class Rates {
#XmlElement(name = "Rate")
private List<Rate> rates;
}
#XmlAccessorType(XmlAccessType.FIELD)
class Rate {
#XmlElement(name = "Currency")
private String currency;
#XmlElement(name = "Code")
private String code;
#XmlElement(name = "Mid")
private Double mid;
}
Currency is apparently not serializable because it doesn't have a parameterless contructor. One workaround is to add a getter that returns a Currency, parsed from the String:
#XmlAccessorType(XmlAccessType.FIELD)
class Rate {
#XmlElement(name = "Currency")
private String currency;
#Xml Element(name = "Code")
private String code;
#XmlElement(name = "Mid")
private Double mid;
public Currency getCurrency() {
return Currency.getInstance(currency);
}
}

JAXB: need to set namespace dynamically

JAXB annotated class:
#XmlRootElement(name = "group")
#XmlType(propOrder = {"name", "description", "types" })
public class GroupElement implements Serializable {
private static final long serialVersionUID = 1L;
private long id;
private String description;
private String name;
private List<TypeElement> types;
#XmlTransient
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#XmlElement(name = "description")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#XmlElement(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlElement(name = "type")
public List<TypeElement> getTypes() {
return types;
}
public void setTypes(List<TypeElement> types) {
this.types= types;
}
}
java-package.info
#XmlSchema(namespace = "http://www.test.at/r1/v1" ,
elementFormDefault = XmlNsForm.QUALIFIED,
xmlns={#XmlNs(prefix="cdr1", namespaceURI="http://www.test.at/r1/v1")})
JAXB marshalling:
JAXBContext jaxbContext = JAXBContext.newInstance(Group.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(group, sw);
I need to set the namespace dynamically depending on the group. With the package-info approach I get the same namespace in every XML file.
I also tried
JAXBElement<Group> element = new JAXBElement<Group>(new
QName(latestStructure.getNamespace(), "group", "cdr1"),
Group.class, group);
But With this approach only the root element gets the namespace and prefix assigned.
Does anyone have an idea how to do this?
You could remove namespace info from the class and package, but create object factories with qualified names (so as many object factories as many namespaces),
#XmlRegistry
public class ObjectFactory {
...
}
and then use the correct factory to initiate your context instead of the Group class:
JAXBContext.newInstance(ObjectFactory.class);
For me easier would be to again use beans without namespaces, marshall to namespace free xml and transform the xml using xslt to add correct "dynamic" namespace as required.

XML parsing returns 40 counts of IllegalAnnotationExceptions

I am trying to parse the XML response to an object but it throws exception.
The link of response is this:
<response>
<meta>
<per_page>10</per_page>
<total>20</total>
<geolocation>None</geolocation>
<took>8</took>
<page>1</page>
</meta>
<events>
<event>
...
</event>
<event>
...
</event>
....
</events>
</response>
Code
queryString = queryString.replaceAll(" ", "%20");
try {
URL page = new URL(queryString);
HttpURLConnection conn = (HttpURLConnection) page.openConnection();
conn.connect();
InputStreamReader in = new InputStreamReader(conn.getInputStream(),Charset.forName("UTF-8"));
this.response = (Response) JAXB.unmarshal(in, Response.class);
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
Exception
javax.xml.bind.DataBindingException: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 40
counts of IllegalAnnotationExceptions
Class has two properties of the same name "events"
this problem is related to the following location:
....
Object classes
#XmlRootElement(name = "Response")
public class Response {
#XmlElement(name="per_page")
private int per_page;
#XmlElement(name="total")
private int total;
#XmlElement(name="geolocation")
private String geolocation;
#XmlElement(name="took")
private int took;
#XmlElement(name="page")
private int page;
#XmlElement(name="events")
private List<Event> events = null;
**getters and setters**
Objects
#XmlRootElement(name="event")
public class Event {
#XmlElement(name = "links")
private String link;
#XmlElement(name = "id")
private int id;
#XmlElement(name = "stats")
private Stats stats;
#XmlElement(name = "title")
private String title;
#XmlElement(name = "announce_date")
private String announce_date;
#XmlElement(name = "score")
private float score;
#XmlElement(name = "date_tbd")
private boolean date_tbd;
#XmlElement(name = "type")
private String type;
#XmlElement(name = "datetime_local")
private String datetime_local;
#XmlElement(name = "visible_until_utc")
private String visible_util_utc;
#XmlElement(name = "time_tbd")
private boolean time_tbd;
#XmlElement(name = "taxonomies")
private List<Taxonomie> taxonomies;
#XmlElement(name = "performers")
private List<Performer> performers;
#XmlElement(name = "url")
private String url;
#XmlElement(name = "created_at")
private String created_at;
#XmlElement(name = "venue")
private Venue venue;
#XmlElement(name = "short_title")
private String short_title;
#XmlElement(name = "datetime_utc")
private String datetime_utc;
#XmlElement(name = "datetime_tbd")
private boolean datetime_tbd;
**getters and setters**
By default JAXB implementations treat public fields and properties as mapped. When you annotate a non-public field it also becomes mapped. Then if you have a mapped field an property with the same name you will get this exception.
When you annotate fields you need to annotate your class with #XmlAccessorType(XmlAccessType.FIELD).
http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html
Note:
You are currently adding more annotations on your model than you need to. Since JAXB is configuration by exception you only need to add annotations where you want the XML representation to differ from the default.
http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html

Categories

Resources