If I have a generated source like
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"position"
})
#XmlRootElement(name = "child")
public class Child implements Serializable, Equals2, HashCode2, ToString2
{
And I want it to read
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"position"
})
#XmlRootElement(name = "child")
public class Child implements Parent, Equals2, HashCode2, ToString2
{
where parent is just
import java.io.Serializable;
public interface Parent extends Serializable
{
}
How do I go about changing the xml?
Related
I cannot unmarshall a generic Type, like this.
I do not like it solve with an adapter class.
Can someone help..
interface Car {
}
class Car1 implements Car {
}
class Car2 implements Car {
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType( name = "", propOrder = { "car1" } )
#XmlRootElement(name = "Element")
class Element{
#XMLELEMENT(type="Car1.class" name="Car")
private Car car1;
}
If the xml you try to unmarshall has different tag for describing car1 and car2, then it is possible by using #XmlElements annotation.
I am creating a small example below to show case it:
#XmlRootElement
public class SomeRoot {
#XmlElements({
#XmlElement(type = Car1.class, name = "car1"),
#XmlElement(type = Car2.class, name = "car2")
})
private List<Car> cars;
}
Then your interface:
public interface Car {
}
A base class with some common field:
#XmlAccessorType(XmlAccessType.FIELD)
public class BaseCar {
private String type;
}
And implementation for car1:
#XmlAccessorType(XmlAccessType.FIELD)
public class Car1 extends BaseCar implements Car {
private String car1SpecificField;
}
and car2:
#XmlAccessorType(XmlAccessType.FIELD)
public class Car2 extends BaseCar implements Car {
private String car2SpecificField;
}
This would unmarshal the xml below fine:
<someRoot>
<car1>
<type>some type</type>
<car1SpecificField>some value</car1SpecificField>
</car1>
<car2>
<type>other type</type>
<car2SpecificField>other value</car2SpecificField>
</car2>
</someRoot>
If your xml has the <car> instead of <car1> and <car2> you need to use an adapter or else jaxb doesn't know to which class to unmarshall.
I have a Root Class called Employee, which has two elements empid and name and another jaxb class called Address. Below is the sample snippet.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Request",propOrder = {
"header",
"body",
"signature"
})
#XmlRootElement(name="Employee")
public class Employee
implements Serializable
{
#XmlElement(name = "Header", required = true)
protected String empId;
#XmlElement(name = "Body", required = true)
protected String empName;
#XmlElement(name = "Address", required = true)
protected Address address;
.. setters and getters
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Address", propOrder = {
"streetLine1",
"streetLine2",
})
#XmlRootElement(name="Address",namespace= "http://www.w3.org/2000/09/xmldsig#")
public class Employee
implements Serializable
{
private final static long serialVersionUID = 100L;
#XmlElement(name = "addressLine1", required = true)
protected String addressLine1;
#XmlElement(name = "addressLine2", required = true)
protected String addressLine2;
//Setters and getters
}
Now when I generate the XML string with jaxb marshalling I want the expected result like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Employee xmlns="http://www.test.com">
<empId>124</empId>
<empName>name</empName>
<Address xmlns:ns2="http://www.w3.org/2000/09/xmldsig#">
<ns2:streetLine1 Id="line1"/>
<ns2:streetLine2 Id="Line2"/>
</Address>
</Request>
Please suggest. Thanks in Advance.
There are some problems with your JAXB classes, I think you have copy pasted and changed some names wrongly. The following elements inside #XMLType must be defined as #XMLElement.
#XmlType(name = "Request",propOrder = {
"header",
"body",
"signature"
})
Anyways assuming the classes are right. You will need 2 changes to generate XML that has elements referred in different namespace.
Move the namespace to package level using #XMLSchema. i.e Add package-info.java at the package level to specify the namespaces.
Provide Address element with its own namespace in Employee class. Each element if not in parent namespace, must be overridden at this level.
package-info.java
#XmlSchema(
namespace = "http://www.test.com",
elementFormDefault = XmlNsForm.QUALIFIED)
package int1.d;
import javax.xml.bind.annotation.*;
Employee.java
package int1.d;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Request",propOrder = {
"header",
"body",
"signature"
})
#XmlRootElement(name="Employee")
public class Employee
implements Serializable
{
private static final long serialVersionUID = 8293193254658211943L;
#XmlElement(name = "Header", required = true)
protected String empId;
#XmlElement(name = "Body", required = true)
protected String empName;
#XmlElement(name = "Address", namespace="http://www.w3.org/2000/09/xmldsig#", required = true )
protected Address address;
public String getEmpId() {
return empId;
}
public void setEmpId(String empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
package-info.java
#XmlSchema(
namespace = "http://www.w3.org/2000/09/xmldsig#",
elementFormDefault=XmlNsForm.QUALIFIED )
package int1.d2;
import javax.xml.bind.annotation.*;
Address.java
package int1.d2;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Address", propOrder = {
"streetLine1",
"streetLine2",
})
#XmlRootElement(name="Address")
public class Address
implements Serializable
{
private final static long serialVersionUID = 100L;
#XmlElement(name = "addressLine1", required = true)
protected String addressLine1;
#XmlElement(name = "addressLine2", required = true)
protected String addressLine2;
public String getAddressLine1() {
return addressLine1;
}
public void setAddressLine1(String addressLine1) {
this.addressLine1 = addressLine1;
}
public String getAddressLine2() {
return addressLine2;
}
public void setAddressLine2(String addressLine2) {
this.addressLine2 = addressLine2;
}
}
output generated by JAXB
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Employee xmlns="http://www.test.com" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#">
<Header>124</Header>
<Body>bae</Body>
<ns2:Address>
<ns2:addressLine1>line1</ns2:addressLine1>
<ns2:addressLine2>line2</ns2:addressLine2>
</ns2:Address>
</Employee>
I am trying to read a JSON file like:
{
"a": "abc",
"data" : {
"type" : 1,
...
}
}
where the ... part is replaceable based on the type like:
{
"a": "abc",
"data" : {
"type" : 1,
"b" : "bcd"
}
}
or:
{
"a": "abc",
"data" : {
"type" : 2,
"c" : "cde",
"d" : "def",
}
}
For the life of me I cannot figure out the proper JAXB annotations/classes to use to make this happen.
I don't have an issue moving the type variable outside of the data block if needed.
I'm using Glassfish 3.1.2.2.
Edit:
Based on the code provided by Perception I did a quick attempt... doesn't work in glassfish though:
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = As.PROPERTY, property = "type")
#JsonSubTypes(
{
#JsonSubTypes.Type(value = DataSubA.class, name = "1"),
#JsonSubTypes.Type(value = DataSubB.class, name = "2")
})
#XmlRootElement
public abstract class Data implements Serializable
{
private static final long serialVersionUID = 1L;
public Data()
{
super();
}
}
#XmlRootElement
#XmlAccessorType(XmlAccessType.NONE)
public class DataSubA
extends Data
{
private static final long serialVersionUID = 1L;
#XmlElement
private BigDecimal expenditure;
public DataSubA() {
super();
}
public DataSubA(final BigDecimal expenditure) {
super();
this.expenditure = expenditure;
}
#Override
public String toString() {
return String.format("%s[expenditure = %s]\n",
getClass().getSimpleName(), getExpenditure());
}
public BigDecimal getExpenditure() {
return expenditure;
}
public void setExpenditure(BigDecimal expenditure) {
this.expenditure = expenditure;
}
}
#XmlRootElement
#XmlAccessorType(XmlAccessType.NONE)
public class DataSubB
extends Data
{
private static final long serialVersionUID = 1L;
#XmlElement
private String name;
#XmlElement
private Integer age;
public DataSubB()
{
super();
}
public DataSubB(final String name, final Integer age)
{
super();
this.name = name;
this.age = age;
}
#Override
public String toString()
{
return String.format("%s[name = %s, age = %s]\n",
getClass().getSimpleName(), getName(), getAge());
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
#XmlRootElement
#XmlAccessorType(XmlAccessType.NONE)
public class DataWrapper
{
#XmlElement
private Data data;
public Data getData() {
return data;
}
public void setData(Data data) {
this.data = data;
}
}
And a simple POST that takes it in:
#Stateless
#Path("x")
public class Endpoint
{
#POST
#Consumes(
{
MediaType.APPLICATION_JSON,
})
#Produces(
{
MediaType.APPLICATION_JSON,
})
public String foo(final DataWrapper wrapper)
{
return ("yay");
}
}
When I pass in JSON like:
{
"data" :
{
"type" : 1,
"expenditure" : 1
}
}
I get a message like:
Can not construct instance of Data, problem: abstract types can only be instantiated with additional type information
at [Source: org.apache.catalina.connector.CoyoteInputStream#28b92ec1; line: 2, column: 5] (through reference chain: DataWrapper["data"])
On the DataClass add an #XmlSeeAlso annotation that specifies all of the subclasses:
#XmlRootElement
#XmlSeeAlso({DataSubA.class, DataSubB.class})
public abstract class Data implements Serializable {
Then on each of the subclasses use the #XmlType annotation to specify the type name.
#XmlType(name="1")
public class DataSubA extends Data {
UPDATE
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
The JAXB (JSR-222) specification doesn't cover JSON-binding. There are different ways JAX-RS allows you to specify JSON mapping via JAXB annotations:
A JAXB implementation plus a library like Jettison that converts StAX events to JSON (see: http://blog.bdoughan.com/2011/04/jaxb-and-json-via-jettison.html)
By leveraging a JAXB impl that offers a JSON-binding (see: http://blog.bdoughan.com/2011/08/json-binding-with-eclipselink-moxy.html)
Leveraging a JSON-binding tool that offers support for some JAXB metadata (i.e Jackson).
Since your model doesn't seem to be reacting as expected to the annotations I'm guessing you are using scenario 3. Below I will demonstrate the solution as if you were using scenario 2.
DataWrapper
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class DataWrapper {
private String a;
private Data data;
}
Data
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlSeeAlso({DataSubA.class, DataSubB.class})
public class Data {
}
DataSubA
import javax.xml.bind.annotation.XmlType;
#XmlType(name="1")
public class DataSubA extends Data {
private String b;
}
DataSubB
import javax.xml.bind.annotation.XmlType;
#XmlType(name="2")
public class DataSubB extends Data {
private String c;
private String d;
}
jaxb.properties
To specify MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html):
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
JAXBContext jc = JAXBContext.newInstance(new Class[] {DataWrapper.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StreamSource json = new StreamSource("src/forum16429717/input.json");
DataWrapper dataWrapper = unmarshaller.unmarshal(json, DataWrapper.class).getValue();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(dataWrapper, System.out);
}
}
input.json/Output
MOXy can read in the numeric value 2 as the inheritance indicator, but currently it will always write it out as "2". I have opened the following enhancement request to address this issue: http://bugs.eclipse.org/407528.
{
"a" : "abc",
"data" : {
"type" : "2",
"c" : "cde",
"d" : "def"
}
}
For More Information
The following link will help you use MOXy in a JAX-RS implementation.
http://blog.bdoughan.com/2012/05/moxy-as-your-jax-rs-json-provider.html
There is a pseudo code like this:
Alma alma = new Alma();
alma.setKorte(""); //Korte is a string member
marshaller.marshal(alma, stringwriter);
System.out.println(stringwriter.toString());
And it produces the output of (I know this is some kind of trick that the empty element is there, but this is how it works in my system, so someone before me have set this like this):
<alma><korte/></alma>
Which is fine for me. But when I unmarshal it, the empty string is not unmarshalled correctly, but korte will be null. How to make jaxb to unmarshal the empty element into empty string?
I use JDK6 bundled jaxb.
EDIT:
The alma class looks like (name of class is changed, but it is like this):
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Alma", propOrder = {
"korte"
})
public class Alma
implements Serializable
{
private final static long serialVersionUID = 100L;
#XmlElement(required = true)
protected String korte;
JAXB implementations should unmarshal empty elements as "" for String properties. The solution will be to upgrade to a newer version of your JAXB implementation that contains this fix.
The example below worked for me using the version of JAXB included in JDK 1.6.0_20 and EcliseLink JAXB (MOXy) 2.3.
Demo
import java.io.StringReader;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Alma.class);
String xmlString = "<alma><korte/></alma>";
StringReader xmlReader = new StringReader(xmlString);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Alma alma = (Alma) unmarshaller.unmarshal(xmlReader);
System.out.println(alma.getKorte().length());
}
}
Output
0
Alma
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement
#XmlType(name = "Alma", propOrder = { "korte" })
public class Alma implements Serializable {
private final static long serialVersionUID = 100L;
#XmlElement(required = true)
protected String korte;
public String getKorte() {
return korte;
}
public void setKorte(String korte) {
this.korte = korte;
}
}
I have an xsd definition (from www.tmforum.org ossj common api v1.5)
<element name="primaryKey" nillable="false">
<complexType mixed="false">
<complexContent mixed="false">
<extension base="anyType"/>
</complexContent>
</complexType>
</element>
and would like to generate an xml as follows
<ossj-co-v1-5:primaryKey>mykey</ossj-co-v1-5:primaryKey>
The PrimaryKey class generated from the xsd using xjc requires a DOM Element to be stored in a list (see the generated PrimaryKey class at the bottom". "myKey" here is a TextNode and since its not an DOM Element, it cannot be added to xjc generated PrimaryKey class. How should I proceed to get the required output?
Here is the PrimaryKey class generated from the xsd
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"any"
})
public static class PrimaryKey {
#XmlAnyElement
protected List<Element> any;
#XmlAnyAttribute
private Map<QName, String> otherAttributes = new HashMap<QName, String>();
public List<Element> getAny() {
if (any == null) {
any = new ArrayList<Element>();
}
return this.any;
}
public Map<QName, String> getOtherAttributes() {
return otherAttributes;
}
}
The following object models would work for your scenario. I'll try to dig up the approprate schema customizations to produce these object models.
Option #1
You could have your code look like the following. This would mean that the element "primaryKey" would cause the object PrimaryKey to be instantiated with the corresponding text content being set on the any property.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {"any" })
public static class PrimaryKey {
#XmlValue
protected String any;
#XmlAnyAttribute
private Map<QName, String> otherAttributes = new HashMap<QName, String>();
public List<Element> getAny() {
if (any == null) {
any = new ArrayList<Element>();
}
return this.any;
}
public Map<QName, String> getOtherAttributes() {
return otherAttributes;
}
}
Option #2
If you want an outer object to have a String property corresponding to the primaryKey you could do the following:
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
// #XmlElement is implied
private String primaryKey;
}
The Option#1 getAny() cannot return String as the signature returns List.
The Option#2 indeed works. Thanks!
Here is how my OSSJ code modification looks:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "ManagedEntityKey", propOrder = {
"applicationContext",
"applicationDN",
"type",
"primaryKey"
})
public class ManagedEntityKey {
#XmlElement(required = true)
protected String primaryKey;
//protected ManagedEntityKey.PrimaryKey primaryKey;
And ofcourse the signature of the setters and getters should be modified.