I'm trying to integrate with a third-party system and depending on the type of object, the root element of the returned XML document changes. For example:
GET /objecttype1-1/ returns:
<?xml version="1.0" encoding="UTF-8"?>
<objecttype1 xmlns="path">
<id>1</id>
<description>obj1</description>
</objecttype1>
and:
GET /objecttype2-3 returns:
<?xml version="1.0" encoding="UTF-8"?>
<objecttype2 xmlns="path">
<id>3</id>
<address>home</address>
</objecttype2>
Since the sub-elements are not guaranteed to be the same (other than id), I figured a List with #XmlMixed #XmlAnyElement will take care of them. But how do I map the root elements? #XmlRootElement(name="???")
Due to technology limitations, I'm not able to use EclipseLink/MOXy. Thanks.
Its been 5 years since this question was asked but I found working solution of the issue, sharing for the community.
First we define JAXB beans as follows:
#XmlRootElement(name = "objecttype1")
#XmlAccessorType(XmlAccessType.NONE)
public class Objecttype1 {
#XmlElement(name = "id")
private String id;
#XmlElement(name = "description")
private String description;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
#XmlRootElement(name = "objecttype2")
#XmlAccessorType(XmlAccessType.NONE)
public class Objecttype2 {
#XmlElement(name = "id")
private String id;
#XmlElement(name = "address")
private String address;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setDescription(String address) {
this.address = address;
}
}
Next we need the JAXB context and the unmarshaller itself:
private static final JAXBContext jaxbContext;
public Unmarshaller getUnmarshaller() {
try {
return jaxbContext.createUnmarshaller();
} catch (JAXBException ex) {
throw new IllegalStateException(ex);
}
}
Having that, the JAXB context is loading its candidates and checks if there is a match amongs them by the root element name. We just unmarshal and check whats the type of received object:
try {
Object unmarshalledObject = getUnmarshaller().unmarshal(new StringReader(xmlString));
if (unmarshalledObject instanceof Objecttype1) {
//do Objecttype1 related work
} else if (unmarshalledObject instanceof Objecttype2) {
//do Objecttype2 related work
} else {
// unexpected object type
}
} catch (JAXBException ex) {
//handle ex
}
Related
I need to Unmarshal XML to Java Object, I have tried with below code but it is giving exception-
Main Class-
JAXBContext context = JAXBContext.newInstance(SimpleBean.class);
Unmarshaller unMarshaller = context.createUnmarshaller();
File file = ResourceUtils.getFile("classpath:config/SimpleBean.xml");
SimpleBean param = (SimpleBean) unMarshaller.unmarshal(new FileInputStream(file));
LOGGER.info("param: "+param.getRoot());
SimpleBean.java
#JsonIgnoreProperties(ignoreUnknown=true)
public class SimpleBean {
#JsonProperty("root")
private Root root;
public Root getRoot() {
return root;
}
public void setRoot(Root root) {
this.root = root;
}
}
Root.java
public class Root {
#JsonProperty("Schedule")
private List<Schedule> schedule;
public List<Schedule> getSchedule() {
return schedule;
}
public void setSchedule(List<Schedule> schedule) {
this.schedule = schedule;
}
}
Schedule.java
#JsonIgnoreProperties(ignoreUnknown=true)
public class Schedule {
#JsonProperty("ID")
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
SimpleBean.xml
<root>
<Schedule ID="561"></Schedule>
<Schedule ID="562"></Schedule>
</root>
Exception coming-
javax.xml.bind.UnmarshalException: unexpected element (uri:"",
local:"root"). Expected elements are (none)
You need to define an #XmlRootElement like this:
#XmlRootElement(name="root")
public class Root {
#JsonProperty("Schedule")
private List<Schedule> schedule;
public List<Schedule> getSchedule() {
return schedule;
}
public void setSchedule(List<Schedule> schedule) {
this.schedule = schedule;
}
}
Also, you don't need another wrapper POJO (SimpleBean).
You should do this directly (otherwise you'll get ClassCastException):
Root param = (Root) unMarshaller.unmarshal(new FileInputStream(file));
LOGGER.info("param: "+param);
This is a working solution-
SomeRoot.java-
#XmlRootElement(name="root")
public class SomeRoot{
private List<Schedule> schedule;
#XmlElement(name = "Schedule")
public List<Schedule> getSchedule() {
return schedule;
}
public void setSchedule(List<Schedule> schedule) {
this.schedule = schedule;
}
}
Schedule.java -
public class Schedule {
private String id;
#XmlAttribute(name = "ID")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
And then in java code-
JAXBContext context = JAXBContext.newInstance(SomeRoot.class);
Unmarshaller unMarshaller = context.createUnmarshaller();
File file = ResourceUtils.getFile("classpath:config/SomeRoot.xml");
SomeRoot param = (SomeRoot) unMarshaller.unmarshal(file);
List<Schedule> schedules = param.getSchedule();
for (Schedule schedule : schedules) {
LOGGER.info("Schedule: "+schedule.getId());
}
I keep getting the same error whenever I try to delete an entity using Morphia:
org.mongodb.morphia.query.ValidationException: The field '_id' could not be found in ...
while validating - _id; if you wish to continue please disable validation.
I don't really want to disable validation. I just want to delete the object.
Here is my delete method of the service I'm writing:
public void delete(ObjectId id) {
BaseMaterial baseMaterial = this.findOne(id);
WriteResult writeResult = this.repo.delete(baseMaterial);
}
and here is the findOne method in the same service (i.e. this.findOne)
public BaseMaterial findOne(ObjectId id) {
Query<BaseMaterial> query = repo.createQuery(BaseMaterial.class);
return Optional.ofNullable(query.field("id").equal(id).get())
.orElseThrow(() -> new DataRetrievalFailureException(
"Failed to fetch " + this.getClass().getName() + " with id " + id.toString()));
}
And here is my POJO:
#Entity("baseMaterial")
public class BaseMaterial {
#Id
#NotNull
protected ObjectId id;
#NotEmpty
private String name;
private String description;
public String get_id() {
return this.id.toString();
}
#JsonIgnore
public ObjectId getId() {
return id;
}
public void setId(ObjectId id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
The findOne method of shown above works as expected so I really have no idea why this is happening.
Any ideas?
I don't see a field annotated with #Id...
This is my class structure:
#XmlRootElement(name="System")
public class SystemDTO () {
#XmlElement(name="ID")
public void setId(String id) {
this.id = id;
}
#XmlElement(name="Source")
public void setSource(SourceDTO source) {
this.source = source;
}
}
#XmlRootElement(name="Source")
class SourceDTO {
#XmlElement(name="Name")
public void setName(String name) {
this.name = name;
}
}
This is my XML File:
<System>
<ID>e5b160d0</ID>
<Source>
<Name>Kron</Name>
</Source>
</System>
The problem is the Source is always null. I do not get a exception, it just comes out null. I've attempted to use just the Source tag and it picks up Name just fine, but when I add it as part of the System class it does not seem to work.
Additionally I attempted to do this and have a string member variable in System for name:
#XmlElementWrapper(name="Source")
#XmlElement(name="Name")
But that causes an exception. Any ideas?
The Test Class
public class JaxbTest {
public static void main(String[] args) {
String xml = "<System>\n" +
" <ID>e5b160d0</ID>\n" +
" <Source>\n" +
" <Name>Kron</Name>\n" +
" </Source>\n" +
"</System>";
SystemDTO systemDTO;
try {
JAXBContext jaxbContext = JAXBContext.newInstance(SystemDTO.class);
StringReader reader = new StringReader(xml);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
systemDTO = (SystemDTO) jaxbUnmarshaller.unmarshal(reader);
System.out.println(systemDTO.getSource().getName());
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
Source DTO
#XmlRootElement(name = "Source")
class SourceDTO {
private String name = null;
public String getName() {
return name;
}
#XmlElement(name = "Name")
public void setName(String name) {
this.name = name;
}
}
System DTO
#XmlRootElement(name = "System")
public class SystemDTO {
private String id;
private SourceDTO source;
public String getId() {
return id;
}
public SourceDTO getSource() {
return source;
}
#XmlElement(name = "ID")
public void setId(String id) {
this.id = id;
}
#XmlElement(name = "Source")
public void setSource(SourceDTO source) {
this.source = source;
}
}
One possible problem that I see is that you have declared 2 "Root" elements in your XML. Try #XmlType on your Source class:
#XmlType(name="Source")
class SourceDTO {
...
}
I am using JAXB API for mapping a Java object to XML. My Java class is
#XmlRootElement(name = "ad")
#XmlAccessorType(XmlAccessType.FIELD)
class Item {
#XmlElement(name = "id", nillable = false)
#XmlCDATA
private int id;
#XmlElement(name = "url", nillable = false)
#XmlCDATA
private String url;
public Item() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
Output is like this :
<ad>
<id><![CDATA[ 104 ]]></id>
<url><![CDATA[www.google.com]]></url>
</ad>
I need to add an attribute to url element, for example :
<ad>
<id><![CDATA[ 104 ]]></id>
<url type="fr"><![CDATA[www.google.fr]]></url>
</ad>
I have tried many combinaisons using #XmlValue and #XmlAttribute ...
Your url variable should not be a String, but should be its own type. You should create a separate class for the url item, Url, and give it a String field, type, with an #XmlAttribute annotation.
For example,
#XmlRootElement(name = "ad")
#XmlAccessorType(XmlAccessType.FIELD)
class Item {
#XmlElement(name = "id")
private int id;
#XmlElement(name = "url")
private Url url;
public Item() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
// #XmlAttribute
public Url getUrl() {
return url;
}
public void setUrl(Url url) {
this.url = url;
}
}
#XmlRootElement(name = "url")
#XmlAccessorType(XmlAccessType.FIELD)
class Url {
#XmlValue
private String value;
#XmlAttribute(name = "type")
private String type;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
Note that I don't have MOXY so I can't use or test your #XmlCDATA annotation.
How we can add field as an attribute for an element for java REST API
My Java class
#XmlRootElement(name = "rtml_application")
public class ApplicationsEntity extends BaseEntity {
private static final long serialVersionUID = 3256446889040622647L;
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
private String path;
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I want to generate xml response
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<rtml_application>
<created_at type="datetime">2013-06-13T12:33:09.885+05:30</created_at>
<id type="integer">9</id>
<name type="string">REST TEST</name>
<path nil="true"></path>
</rtml_application>
could any please help me out fix this problem using java annotation with jersey.
#XmlAttribute designates a field as an attribute, rather than an element