I have below xml structure:
<Response>
<Field1>
<User>
<Name>abc</Name>
<Id>1</Id>
</User>
</Field1>
<Field2>
<User>
<Name>sdf</Name>
<Id>2</Id>
</User>
</Field2>
<Field3>
<User>
<Name>xyz</Name>
<Id>3</Id>
</User>
</Field3>
...
</Response>
There are different Field(X) wrapper elements which contain the same User element. There can be n number of Fields sent in the XML. Due to this I cannot have the separate Jaxb's for each. I need to get access to the User ignoring the Field elements after the unmarshalling step. Unfortunately I dont have access to change the xml structure. I am unable to find a solution for it. Any pointers will be helpful.
You can do something like this on you Response (root) class:
#XmlRootElement(name = "Response")
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
#XmlElements(value = {
#XmlElement(name = "Field1", type = Field.class),
#XmlElement(name = "Field2", type = Field.class),
#XmlElement(name = "Field3", type = Field.class)
})
private Field field;
}
JAXB would automatically map to field class whenever it encounters the different FIelds.
EDITED/UPDATED
XML:
<Response>
<Field1>
<Name>abc</Name>
<Id>1</Id>
</Field1>
<Field2>
<Name>sdf</Name>
<Id>2</Id>
</Field2>
<Field3>
<Name>xyz</Name>
<Id>3</Id>
</Field3>
</Response>
Root:
#XmlRootElement(name = "Response")
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
#XmlAnyElement
private List<Field> action;
}
Field:
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Field {
private String Name;
private String Id;
}
Main:
public class Main {
public static void main(String[] args) throws JAXBException, XMLStreamException {
final InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("sample.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(Root.class).createUnmarshaller();
final Root root = unmarshaller.unmarshal(xmlStreamReader, Root.class).getValue();
System.out.println(root.toString());
Marshaller marshaller = JAXBContext.newInstance(Root.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(root, System.out);
}
}
Output:
Root(action=[[Field1: null], [Field2: null], [Field3: null]])
<Response>
<Field1>
<Name>abc</Name>
<Id>1</Id>
</Field1>
<Field2>
<Name>sdf</Name>
<Id>2</Id>
</Field2>
<Field3>
<Name>xyz</Name>
<Id>3</Id>
</Field3>
</Response>
Related
I don't want to use annotations on my class to marshal/unmarshal from XML. i know jaxb does not need annotations to unmarshal xml into an object as long as the property names and the structure match. it works with numbers and strings but it does not seem to work with Booleans. these always end up as nulls, and when marshalling, Boolean properties do not show up in the resulting XML.how can i make it work without using annotations?
You will at least need the #XmlRootElement annotation on your root class.
The preferred naming convention for a boolean getter is isSomething() instead of getSomething().
The following Java class
#XmlRootElement
public class Root {
private Boolean something;
public Boolean isSomething() {
return something;
}
public void setSomething(Boolean something) {
this.something = something;
}
}
works fine for me with this XML input:
<root>
<something>true</something>
</root>
I have tested with this main method:
public static void main(String[] args) throws Exception {
JAXBContext context = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
File file = new File("root.xml");
Root root = (Root) unmarshaller.unmarshal(file);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
The generated XML output is:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<something>true</something>
</root>
I need to generate xml using jaxb as below :
<item>
<key1 id="default">value1</key1>
<key2 id="default">value2</key2>
<key3 id="default">value3</key3>
</item>
how to do this using #XmlPath in jaxb?
i have used below one. But i have multiple keys around 50. how to acheive this?
#XmlPath("key1/#id")
private String attrValue = "default";
#XmlPath is an extension in the EclipseLink MOXy implementation of JAXB (JSR-222). You will need to use the equivalent in MOXy's mapping file to get the desired behaviour.
oxm.xml
What you are looking for is the ability to apply multiple writeable mappings for a field/property. This can't currently be done via annotations, but can be done using MOXy's external mapping document.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum12704491">
<java-types>
<java-type name="Item">
<java-attributes>
<xml-element java-attribute="attrValue" xml-path="key1/#id"/>
<xml-element java-attribute="attrValue" xml-path="key2/#id" write-only="true"/>
<xml-element java-attribute="attrValue" xml-path="key3/#id" write-only="true"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Item
package forum12704491;
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Item {
private String attrValue;
private String key1;
private String key2;
private String key3;
}
jaxb.properties
In order to specify MOXy as your JAXB provider you need to add 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
The demo code below demonstrates how to bootstrap using MOXy's external mapping document.
package forum12704491;
import java.io.File;
import java.util.*;
import javax.xml.bind.*;
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>(1);
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "forum12704491/oxm.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {Item.class}, properties);
File xml = new File("src/forum12704491/input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
Item item = (Item) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(item, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8"?>
<item>
<key1 id="default">value1</key1>
<key2 id="default">value2</key2>
<key3 id="default">value3</key3>
</item>
I have a quite simple question :
Say I have a model class defined like this :
public class Test{
private String testAttribute;
public Test(){
}
public String getFormattedTestAttribute(){
return testAttribute + "A nice formatted thingy"; //right, this is just an example
}
public void setTestAttribute(String value){
testAttribute = value;
}
}
You can see that I have a standard setter for testProperty but the getter has a different name : getFormattedTestProperty().
Is it possible into Jaxb/Moxy to specify which getter to use for a specific property ?
I'm using MOXy implementation with external metadata bindings file. The project which I'm working on used tu use Castor. Into Castor's mapping files, you could specify which getter/setter to use like that :
<field name="testAttribute"
get-method="getFormattedTestAttribute">
<bind-xml name="test-attribute" node="attribute"/>
</field>
Is the same kind of thing possible with moxy's external metadata ?
If that kind of customization isn't supported, is it possible to mark a field as read-only and another as write-only ? so I could declare a read-only property named "formattedTestAttribute" and a write-only property named "testAttribute" into the metadata bindings file ?
<!-- read only property -->
<xml-element java-attribute="formattedTestAttribute" xml-path="#test-attribute" />
<!-- write only property -->
<xml-element java-attribute="testAttribute" xml-path="#test-attribute" />
Please note that I have very limited control over the model classes.
Thanks in advance for your answers.
You could represent this in EclipseLink JAXB (MOXy)'s external mapping document as follows:
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum8834871">
<java-types>
<java-type name="Test" xml-accessor-type="PUBLIC_MEMBER">
<xml-root-element/>
<java-attributes>
<xml-element
java-attribute="testAttribute"
name="test-attribute">
<xml-access-methods
get-method="getFormattedTestAttribute"
set-method="setTestAttribute"/>
</xml-element>
<xml-transient java-attribute="formattedTestAttribute"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Test
I have modified your Test class, to put some logic in the get/set methods.
package forum8834871;
public class Test{
private String testAttribute;
public Test(){
}
public String getFormattedTestAttribute(){
return "APPENDED_ON_GET " + testAttribute;
}
public void setTestAttribute(String value){
testAttribute = "APPENDED_ON_SET " + value;
}
}
Demo
package forum8834871;
import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum8834871/oxm.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {Test.class}, properties);
File xml = new File("src/forum8834871/input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
Test test = (Test) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(test, System.out);
}
}
input.xml
<?xml version="1.0" encoding="UTF-8"?>
<test>
<test-attribute>ORIGINAL</test-attribute>
</test>
Output
<?xml version="1.0" encoding="UTF-8"?>
<test>
<test-attribute>APPENDED_ON_GET APPENDED_ON_SET ORIGINAL</test-attribute>
</test>
I have a java property annotated with #XmlElement(required=false, nillable=true). When the object is marshalled to xml, it is always outputted with the xsi:nil="true" attribute.
Is there a jaxbcontext/marshaller option to direct the marshaller not to write the element, rather than write it with xsi:nil?
I've looked for answers to this and also had a look at the code, afaics, it will always write xsi:nil if nillable = true. Am I missing something?
If the property is annotated with #XmlElement(required=false, nillable=true) and the value is null it will be written out with xsi:nil="true".
If you annotate it with just #XmlElement you will get the behaviour you are looking for.
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
Example
Given the following class:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
#XmlElement(nillable=true, required=true)
private String elementNillableRequired;
#XmlElement(nillable=true)
private String elementNillbable;
#XmlElement(required=true)
private String elementRequired;
#XmlElement
private String element;
}
And this demo code:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Root root = new Root();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
The result will be:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<elementNillableRequired xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<elementNillbable xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</root>
I want to know how to implement having List of interface Type using EclipseLink MOXy,
Before, using JAXB , The following annotations did the job
class A {
#XmlElements({
#XmlElement(name = "B1", type = B1.class),
#XmlElement(name = "B2", type = B2.class)
})
List< B > list;
}
interface B{}
class B1 implements B {}
class B2 implements B {}
to support List of interface type ???
I lead EclipseLink JAXB (MOXy). I am not able to reproduce your issue. Could you provide the stack trace you are seeing? The following is what I have tried:
Demo
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.Version;
public class Demo {
public static void main(String[] args) throws Exception {
System.out.println(Version.getVersionString());
JAXBContext jc = JAXBContext.newInstance(A.class, B1.class, B2.class);
System.out.println(jc);
File xml = new File("input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBElement<A> root = unmarshaller.unmarshal(new StreamSource(xml), A.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
jaxb.properties
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
input.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
<B1/>
<B2/>
</root>
Output
2.2.0.v20110202-r8913
org.eclipse.persistence.jaxb.JAXBContext#11ddcde
<?xml version="1.0" encoding="UTF-8"?>
<root>
<B1/>
<B2/>
</root>
Using EclipseLink JAXB (MOXy)'s XML Metadata File
MOXy also has an extension to provide the metadata as an XML file. Below is what it would look like for this example:
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="com.example">
<java-types>
<java-type name="A">
<java-attributes>
<xml-elements java-attribute="list">
<xml-element name="B1" type="com.example.B1"/>
<xml-element name="B2" type="com.example.B2"/>
</xml-elements>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
This metadata file is passed in as a property when the JAXBContext is created:
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, new File("src/forum149/bindings.xml"));
JAXBContext jc = JAXBContext.newInstance(new Class[] {A.class, B1.class, B2.class}, properties);
For more information see:
http://bdoughan.blogspot.com/2010/12/extending-jaxb-representing-annotations.html