I am trying to map a xml response given by a web service to a java object using SimpleXML 2.1.0, but i am stuck.
This is the xml:
<QueryINVAP-WS-ASSETResponse baseLanguage="ES" creationDateTime="2016-11-08T17:10:09-03:00">
<INVAP-WS-ASSETSet>
<ASSET rowstamp="265381811">
<ASSETID>1529</ASSETID>
<ASSETNUM>2503</ASSETNUM>
<DESCRIPTION>POWER CHASSIS()</DESCRIPTION>
<ITEMNUM>A000232</ITEMNUM>
<LOCATION>LOCATIONTEST</LOCATION>
<SERIALNUM>123456789</SERIALNUM>
<SITEID>TVD</SITEID>
</ASSET>
</INVAP-WS-ASSETSet>
As you can imagine, the only data I want to convert to a java object are assetid, assetnum, description, itemnum, location, SerialNum and siteid.
Until now this is what I have:
#Root(name = "QueryINVAP-WS-ASSETResponse", strict = false)
public class Activos {
#ElementList(inline = true, entry = "ASSET", type = Activo.class)
private List<Activo> activos;
#Root
class Activo {
#Attribute(name = "rowstamp")
public String rowstamp;
#Element(name = "ASSETID")
public Integer assetid;
#Element(name = "ASSETNUM")
public String assetnum;
#Element(name = "DESCRIPTION")
public String description;
#Element(name = "LOCATION")
public String location;
#Element(name = "SERIALNUM")
public String serialnum;
#Element(name = "SITEID")
public String siteid;
}
}
The error I get is:
org.simpleframework.xml.core.ValueRequiredException: Unable to satisfy #org.simpleframework.xml.ElementList(data=false, empty=true, entry=ASSET, inline=true, name=, required=true, type=class invap.invapgestionmovil.modelos.Activos$Activo) on field 'activos' private java.util.List invap.invapgestionmovil.modelos.Activos.activos for class invap.invapgestionmovil.modelos.Activos at line 1
what am I doing wrong?
Well, finally I solved the issue. I created three classes:
#Root(name = "QueryINVAP-WS-ASSETResponse", strict=false)
public class QueryINVAPWSASSETResponse {
#Element(name = "INVAP-WS-ASSETSet")
private INVAPWSASSETSet set;
}
#Root(name = "INVAP-WS-ASSETSet", strict=false)
public class INVAPWSASSETSet {
#ElementList(inline=true, name = "ASSET")
private List<Activo> activos;
}
#Root(name = "ASSET", strict = false)
public class Activo {
#Attribute(name = "rowstamp")
public String rowstamp;
#Element(name = "ASSETID")
public Integer assetid;
#Element(name = "ASSETNUM")
public String assetnum;
#Element(name = "DESCRIPTION")
public String description;
#Element(name = "LOCATION")
public String location;
#Element(name = "SERIALNUM")
public String serialnum;
#Element(name = "SITEID")
public String siteid;
}
Now when I do the call I get the asset "wrapped" with the others two classes.
Hope this help others :)
Regards
Related
I'm working on a Spring Boot + Maven + Restful + Hibernate project! After creating the RestController for adding new Devices in database i'm getting this error:
2018-03-28 10:15:18.786 WARN 9286 --- [nio-9090-exec-9] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.hhm.hsy.hibernate.models.Protocol` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"id":5,"protocolName":"ProtocolForTesting","port":5202}'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.hhm.hsy.hibernate.models.Protocol` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"id":5,"protocolName":"ProtocolForTesting","port":5202}')
at [Source: (PushbackInputStream); line: 1, column: 52] (through reference chain: com.hhm.hsy.hibernate.models.Device["protocol"])
Here is my first entity:
#Entity
#Table(name = "devices", catalog = "hqm")
public class Device implements Serializable {
private static final long serialVersionUID = -8311225474375837513L;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "device_id", unique = true, nullable = false)
private Integer id;
#Column(name = "device_name", unique = true, nullable = false)
private String deviceName;
#ManyToOne
#JoinColumn(name = "protocol_id")
private Protocol protocol;
public Device() {
}
public Device(Integer id, String deviceName, Protocol protocol) {
this.id = id;
this.deviceName = deviceName;
this.protocol = protocol;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public Protocol getProtocol() {
return protocol;
}
public void setProtocol(Protocol protocol) {
this.protocol = protocol;
}
And the second entity:
#Entity
#Table(name = "protocols", catalog = "hqm")
public class Protocol implements Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "protocol_id", unique = true, nullable = false)
private Integer id;
#Column(name = "protocol_name", unique = true, nullable = false, length = 45)
private String protocolName;
#Column(name = "port", nullable = false)
private Integer port;
#OneToMany(mappedBy = "protocol", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Device> devices = new HashSet<>();
public Protocol() {
}
public Protocol(Integer id, String protocolName, Integer port) {
this.id = id;
this.protocolName = protocolName;
this.port = port;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getProtocolName() {
return protocolName;
}
public void setProtocolName(String protocolName) {
this.protocolName = protocolName;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
#JsonIgnore
public Set<Device> getDevices() {
return devices;
}
#JsonIgnore
public void setDevices(Set<Device> devices) {
this.devices = devices;
}
}
Controller:
#RestController
#RequestMapping(value = "/api/devices")
#ComponentScan({"com.hhm.hsy.pmcs.*"})
public class DevicesController {
#Autowired
#Qualifier(value = "deviceService")
GenericServiceIntf deviceService;
// get ALL DEVICE
#RequestMapping(value = "", method = RequestMethod.GET)
public Map<String, Object> getDevices() {
Map<String, Object> devicesMap = new HashMap<>();
devicesMap.put("devices", deviceService.getAll());
return devicesMap;
}
//save a new DEVICE
#RequestMapping(value = "", method = RequestMethod.POST, consumes = {"application/json"}, produces = {"application/json"})
#ResponseStatus(HttpStatus.CREATED)
public ResponseEntity<Device> addDevice(#RequestBody Device device) {
deviceService.save(device);
return ResponseEntity.accepted().body(device);
}
}
Service:
#Service("deviceService")
public class DeviceServiceImpl extends GenericServiceAbstractImpl<Device, Integer> implements Serializable{
private static final long serialVersionUID = 697655212967127150L;
#Autowired
public DeviceServiceImpl(#Qualifier("deviceDao") GenericDaoIntf genericDao) {
super(genericDao);
}
}
So when i'm trying to add a new device, i get the error i mentioned upper.I don't know what is causing this exception. When I try to add with post a new Protocol it's working, table is being created in the database correctly and I am getting the data correctly in GET request as well..Please help me, I'm new to springboot and restful... if some more information is required, please just inform me and i will post it! Thank you!
I tried to reproduce your problem: here, but everything works as expected.
I think it can be related with this bug.
You should try to reproduce bug with different jackson version.
EDIT:
One more thing: It looks like you try to construct Protocol instead of Device. Show us your deviceService, if you can.
Failed to read HTTP message:
org.springframework.http.converter.HttpMessageNotReadableException:
JSON parse error: Cannot construct instance of
`com.hhm.hsy.hibernate.models.Protocol
Newbie to Android and developing an app where using XML parsing with the retrofit.
I have completed all the process and done the task except one.
I don't know how to create the POJO class for the "hours_of_operations" tag in below XML.
A sample code would be a great help.
<dealers>
<dealer>
<name>Minnesota Tile & Stone</name>
<address>
...... </address>
<phone>12345678</phone>
<url>www.xyz.com</url>
<showroom_display_level>ooopppss</showroom_display_level>
<distance>11.76</distance>
<open>false</open>
<hours_of_operations>
<hours_of_operation>
<days>M,W,F</days>
<hours>10:00 - 5:00</hours>
</hours_of_operation>
<hours_of_operation>
<days>T,Th</days>
<hours>10:00 - 8:00</hours>
</hours_of_operation>
<hours_of_operation>
<days>Sat</days>
<hours>10:00 - 4:00</hours>
</hours_of_operation>
</hours_of_operations>
<google_static_map_url>
....... </google_static_map_url>
<google_map_url>
.......</google_map_url>
</dealer>
I have done with all attributes, just not sure about "hours_of_operations" and data inside that. Here is my Dealer class
#Root(name = "dealer")
public class Dealer {
#Element(name = "name")
private String name;
#Element(name = "address")
private Address adress;
#Element(name = "phone")
private long phone;
#Element(name = "url")
private String url;
#Element(name = "showroom_display_level", required = false)
private String showroom_display_level;
#Element(name = "distance")
private String distance;
#Element(name = "open", required = false)
private String open;
#Element(name = "hours_of_operations")
private HoursOfOperation hours_of_operations;
#Element(name = "google_static_map_url")
private String google_static_map_url;
#Element(name = "google_map_url")
private String google_map_url;
--getters--n -setters--
hoursofoperation class
#Root(name = "hours_of_operation", strict = false)
public class HoursOfOperation {
#Element(name = "days", required = false)
private String days;
#Element(name = "hours", required = false)
private String hours;
getters--setters
Here is my response class
#Root(name = "dealers", strict = false)
public class ApiResponse {
#ElementList(inline = true, required = false)
public List<Dealer> dealerList;
}
I am done with this XML, just not sure about the "hours_of_operations"
Thanks in advance.
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);
}
}
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
I have a JPA Entity as
#Entity
#Table(uniqueConstraints = #UniqueConstraint(columnNames = { "name", "market_version" }))
public class Market extends MutableEntity {
#Column(nullable = false)
private String name;
#Column
private String description;
#Column(name = "market_version", nullable = false)
private Version marketVersion;
public Market(final String name, final String description) {
this.name = name;
this.description = description;
this.marketVersion = new Version("1.0", VersionType.MAJOR, VersionStatus.ACTIVE);
} ... snipped
Which contains a Version and Version class looks like
public class Version {
private String name;
private VersionType type;
private VersionStatus status;
private DateTime publishedOn;
private DateTime retiredOn;
private Version parentVersion;
public Version(#Nonnull final String name, #Nonnull final VersionType type, #Nonnull final VersionStatus status) {
this.name = name;
this.type = type;
this.status = status;
}
}
enum VersionType {
MAJOR,
MINOR,
BOTH
}
enum VersionStatus {
ACTIVE,
RETIRED
}
When I try to save the market entity in test,
#Test
public void testMarket() {
final Market market = new Market("test", "test market");
final MarketCrudService crudService = new MarketCrudService(jpaRule.getEntityManager());
crudService.create(market);
}
I see error
Caused by: org.hibernate.MappingException: Could not determine type for: com.myorg.project.versioning.entities.Version, at table: Market, for columns: [org.hibernate.mapping.Column(market_version)]
What exactly is the issue here? How can I fix it?
You either have to make Version a full entity with it's own table like you did with Market or if you want to save it as a part of Market you should make it embeddable using the #Embeddable annotation.
If you make it embeddable then you will have to remove the #Column annotation from the marketVersion field in Market.