JAXB unmarshal child attributes without creation of child class - java

I want to unmarshal a (simplified) XML structure like this:
<parent>
<a>AValue</a>
<b>BValue</b>
<c someAttribute = "true">CValue</c>
</parent>
I know how to do this with declaring a class C like this:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "c", propOrder = {
"someAttribute"
})
public class C{
#XmlValue
private String c;
#XmlAttribute ( name="someAttribute")
private boolean someAttribute;
//getters and setters
}
And getting it as a member in class parent like this:
public class Parent{
private String a;
private String b;
private C c;
//getters and setters for c,b,a
}
This works finde and i can access the value of C via parent.getC().getC();
My Question is how to achieve that i do not have to create a class C and get the value and attribute of C as a member of parent, without editing the parent Pojo with new members and other getters and setters.
I already tried to do this via Listeners and searched for similar structures, but i haven't got any ideas left.

I finally figured out how to achieve this.
Its necessary to use the #XmlJavaTypeAdapter Annotation and mark the C class as an #XmlRootElement as well as an #XmlAccessorType(XmlAccessType.FIELD).
Furthermore one need to use the #XmlTransient on the getter of the String member which was annotated with #XmlJavaTypeAdapter.
Full solution:
Class C:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class C{
#XmlValue
private String c;
#XmlAttribute
private boolean someAttribute;
//getters and setters for both
Class Adapter:
public class Adapter extends XmlAdapter<C, String> {
public String unmarshal(C pC) throws Exception {
//some possible handling with the attribute over pC.getSomeAttribute();
return pC.getC();
}
public C marshal(String pC) throws Exception {
C c = new C();
c.setC(pC)
//some possible handling to set the attribute to c
return c;
}
Class Parent:
public class Parent{
private String a;
private String b;
#XmlJavaTypeAdapter(Adapter.class)
private String c;
#XmlTransient
public String getC() {
return c;
}
//getters and setters for b,a and setter for C
}

Related

JAXB how to nest several objects?

I've been trying to search how to do this but I haven't found an answer to my exact requirements:
Let's say we had this 3 classes:
public class Main {
public ArrayList<MyFirstClass> myFirstClass;
}
class MyFirstClass {
public int num;
public MySecondClass mySecondClass;
}
class MySecondClass {
public String otherStr;
public MyThirdClass myThirdClass;
}
class MyThirdClass {
public int otherNum;
}
I wanto to be able to read these XML with the unmarshaller:
<Main>
<MyFirstClasses>
<MyFirstClass>
<num>1</num>
<MySecondClass>
<str>Hello</str>
<MyThirdClass>
<otherNum>2</otherNum>
</MyThirdClass>
</MySecondClass>
</MyFirstClass>
<MyFirstClasses>
</Main>
Where I'm basically able to set the variables that are objects (MySecond/Third Class).
I know I can use #XMLRootElement and then #XmlElementWrapper(name="aName") and #XmlElement(name="aName") to do the
<Main>
<MyFirstClasses>
<MyFirstClass>
<num>1</num>
</MyFirstClass>
<MyFirstClasses>
</Main>
But how can I then nest the MySecondClass inside MyFirstClass so I can set it's values, because otherwise the FirstClassObject will have a MySecondClass which has null values.
Thanks in advance!
The problem is that your xml does not match your POJOs. You can use annotations to fix this(renaming fields would also work). Try this:
#XmlRootElement(name = "Main")
public class Main {
#XmlElementWrapper(name = "MyFirstClasses")
#XmlElement(name = "MyFirstClass")
private List<MyFirstClass> myFirstClass;
}
Then FirstClass:
#XmlAccessorType(XmlAccessType.FIELD)
public class MyFirstClass {
private int num;
#XmlElement(name = "MySecondClass")
private MySecondClass mySecondClass;
}
And MySecondClass:
#XmlAccessorType(XmlAccessType.FIELD)
public class MySecondClass {
private String str;
#XmlElement(name = "MyThirdClass")
private MyThirdClass myThirdClass;
}
Finally MyThirdClass:
#XmlAccessorType(XmlAccessType.FIELD)
public class MyThirdClass {
public int otherNum;
}

Best way to write pojos that can have common fields

I am currently making a service in which there are lots of public API's. And the response and request objects overlap a lot. So, I was thinking that is there a way by which we can generalise the pojo creation for the request/response objects.
Sometimes the response object is identical to the request object with one or two extra fields.
Let me give you an example.
#Data
public class Request {
private A objA;
private B objB;
}
#Data
public class Response {
private A objA;
private B objB;
private C objC;
}
#Data
public class A {
private D objD;
}
#Data
public class B {
private String sB;
private E obje;
}
#Data
public class C {
private String sC;
}
Similary, D and E are pojos as well. The thing is that there is a lot of similarity(overlapping fields) in request/response objects.
Your solution is probably inheritance: Create a parent abstract object type with the overlapping fields and have the request and response objects extend it and specify any extra (unique) fields they need.
Inheritence
public abstract class Common {
private String overlapfield1;
private String overlapfield2
}
public class Request extends Common {
private String requestField1;
private String requestField2;
}
public class Response extends Common {
private String responseField1;
private String responseField2;
}
You could also approach this using composition: Create an object type with the overlapping fields and include this object as a sub-object of the Request/Response types:
Composition
public class Common {
private String overlapfield1;
private String overlapfield2
}
public class Request {
private String requestField1;
private String requestField2;
private Common common;
}
public class Response {
private String responseField1;
private String responseField2;
private Common common;
}
There are pros and cons to each approach which are widely discussed on this and other boards. These however, are the two standard approaches to dealing with such a problem.
It really depends on what you are trying to achieve. I don't see it being a huge problem repeating the fields but you've given an abstract use case rather than a real world situation where I can understand what you're trying to achieve.
Perhaps you want to pass your #Data objects to the same services? In which case you might want to use interfaces because a class can implement multiple interfaces.
Eg
public interface AContiner {
A getA();
void setA(A a);
}
public interface BContiner {
B getB();
void setB(B b);
}
#Data
public class Bean1 implements AContainer {
private A a;
}
#Data
public class Bean2 implements AContainer, BContainer {
private A a;
private B b;
}
public class MyFantasticService {
public void doStuffWithA(AContainer data) {
System.out.println(data.getA());
}
public void doStuffWithB(BContainer data) {
System.out.println(data.getB());
}
}

how to know the subclass of mapping in hibernate

#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class A{
private long id;
}
#Entity
public class B extends A{
private String bProperty;
}
#Entity
public class C extends A{
private String cProperty;
}
#Entity
public class Person{
#OneToMany
private Set<A> a;
}
when I use person.getVehicles
How can I know the A is B or C?
I'm using instanceof to check and cast it to get bProperty or cProperty.
Is there any other better way?
The only safe way is to use a polymorphic method. Even instanceof will not work because the instance might actually be a proxy, i.e. a subclass of A that is neither a B or a C, but delegates to a B or a C.
public class A{
private long id;
public abstract boolean isB();
public abstract boolean isC();
public abstract String getBProperty();
public abstract String getCProperty();
}
public class B extends A{
private String bProperty;
public boolean isB() {
return true;
}
public boolean isC() {
return false;
}
public String getBProperty() {
return bProperty;
}
public String getCProperty() {
throw new IllegalStateException("I'm not a C");
}
}
To be cleaner, try using the visitor pattern. I've written a blog post about it. It's in French, but it should be easily translatable.

JAXB using #XmlJavaTypeAdapter to marshal a subset of a Collection

I've got an entity which contains a collection of a different type of entities. What I want to do is have JAXB marshal only a select subset of the collection, based on some criteria.
#XmlRootElement
#Entity
public class A{
// other fields
#OneToMany(mappedBy = "x", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Collection<B> bees;
#XmlJavaTypeAdapter(BFormatter.class)
public Collection<B> getBees() {
return bees;
}
public void setBees(Collection<B> bees) {
this.bees= bees;
}
}
#XmlRootElement
#Entity
public class B{
// fields
}
public class BFormatter extends XmlAdapter<Collection<B>, Collection<B>>{
#Override
public Collection<B> unmarshal(Collection<B> v) throws Exception {
return v;
}
#Override
public Collection<B> marshal(Collection<B> v) throws Exception {
Collection<B> subset;
// making subset
return subset;
}
}
This results in errors saying "java.util.Collection is an interface, and JAXB can't handle interfaces" and that "java.util.Collection does not have a no-arg default constructor."
What am I doing wrong, and is this even the right way to go about it?
The important thing is that you can't adapt a Collection (an interface) to something JAXB can handle, since it doesn't marshal an ArrayList or some other collection class. It is designed to marshal (bean) classes containing fields that are Lists or similar, which is meant to "disappear", remaining as the mere repetition of its elements. In other words, there's no XML element representing the ArrayList (or whatever) itself.
Therefore, the adapter has to modify the containing element. (See below for alternatives.) The following classes are working; just assemble a Root element and modify the AFormatter according to your design. (The comments refer to the example at
https://jaxb.java.net/tutorial/section_6_2_9-Type-Adapters-XmlJavaTypeAdapter.html#Type%20Adapters:%20XmlJavaTypeAdapter.)
(Most classes should be modified to avoid making fields public, but as it is, it is brief and working.)
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Root{ // Training
#XmlElement
private A a; // Brochure
public Root(){}
public A getA(){ return a; }
public void setA( A value ){ a = value; }
}
#XmlJavaTypeAdapter(AFormatter.class)
public class A{ // Brochure
private Collection<B> bees;
public A(){
bees = new ArrayList<>();
}
public Collection<B> getBees() {
if( bees == null ) bees = new ArrayList<>();
return bees;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
public class B{ // Course
#XmlElement
private String id;
public B(){}
public String getId(){ return id; }
public void setId( String value ){ id = value; }
}
public class AFormatter extends XmlAdapter<BeeHive, A>{
#Override
public A unmarshal(BeeHive v) throws Exception {
A a = new A();
for( B b: v.beeList ){
a.getBees().add( b );
}
return a;
}
#Override
public BeeHive marshal(A v) throws Exception {
BeeHive beeHive = new BeeHive();
for( B b: v.getBees() ){
if( b.getId().startsWith("a") ) beeHive.beeList.add( b );
}
return beeHive;
}
}
public class BeeHive { // Courses
#XmlElement(name="b")
public List<B> beeList = new ArrayList<B>();
}
Alternatives: It would be quite simple if the regular getter of the B-list would return the ones that should be marshalled. If the application needs to see all, an alternative getter could be added. Or, the class could have a static flag that instructs the getter to return a List to be used for marshalling, or the regular list at other times.

How to write the JAXB object that has attribute and value

Here's my intended XML structure
<Outer type="good" id="1">
<Uid>123</Uid>
<Name>Myself</Name>
<Inner type="bad">This Value</Inner>
</Outer>
Here's my Object.
#XmlAccessorType(XMLAccessType.FIELD)
#XmlType(name="Outer", propOrder = {
"uid"
"name"
"inner"
})
public class Outer{
#XmlElement(name = "Uid")
protected String uid;
#XmlElement(name = "Name")
protected String name;
#XmlElement(name = "Inner")
protected Inner inner;
public static class Inner{
#XmlAttribute
private String type;
#XmlValue
private String value;
//setters & getters for both
}
//setters & getters for all the elements
}
Now in my class I am doing
Outer o = new Outer();
o.setUid/ID/Type/Name() ; //all the setter
Inner i - new Inner();
i.setValue("This Value");
i.setType("bad");
When Irun this i am getting
If a class has #XmlElement property, it cannot have #XmlValue property.
And
Class has two properties of the same name "type" (This one is for the Source class)
And
Class has two properties of the same name "value" (This one is for Source class too)
What is happening, and what I can I do rectify this?
Thanks
Currently, JAXB threats both fields (due to annotations) and both pairs of get/set (due to default accessor type) as properties. So you class Inner has 4 properties.
Please, add own accessor type for Inner class
#XmlAccessorType(XmlAccessType.FIELD)
public static class Inner
{
Or annotate properties instead of fields
public static class Inner
{
private String type;
private String value;
#XmlAttribute
public String getType()
{
return type;
}
// setter setType
#XmlValue
public String getValue()
{
return value;
}
// setter setValue
}
Add XmlRootElement annotation to the Outer class, besides of that it shoud work.
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Outer", propOrder = {"uid", "name", "inner"})
public static class Outer {

Categories