I have a List<SelectConditionHeaderModel> .
When i am marshalling this list, I am getting an error :
javax.xml.bind.MarshalException
- with linked exception:
[com.sun.istack.internal.SAXException2: A cycle is detected in the object graph. This will cause infinitely deep XML
My abstract Parent class.
#XmlRootElement
#XmlSeeAlso({ SelectConditionHeaderModel.class,
SelectConditionModel.class })
public abstract class SelectConditionParentModel {
#XmlInverseReference(mappedBy = "conditionList")
SelectConditionParentModel parent;
public SelectConditionParentModel getParent() {
return parent;
}
public void setParent(HbaseSelectConditionParentModel parent) {
this.parent = parent;
}
}
Header class extending the abstract parent
#XmlRootElement
public class SelectConditionHeaderModel extends
SelectConditionParentModel {
List<SelectConditionParentModel> conditionList;
String header;
public List<SelectConditionParentModel> getConditionList() {
return conditionList;
}
public void setConditionList(List<SelectConditionParentModel> condition) {
this.conditionList = condition;
}
public String getHeader() {
return header;
}
public void setHeader(String header) {
this.header = header;
}
}
Condition class extending the Abstract Parent
#XmlRootElement
public class SelectConditionModel extends SelectConditionParentModel {
String tableName;
public String getTableName() {
return columnFamily;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
}
Please help me out with this . I have also used XMLInverseReference but it seems that it is not working.
Try to use this configuration based on #XmlID and #XmlIDREF.
or you can put #XmlTransient to exclude the subgraph.
If you are using EclipseLink JAXB (MOXy) as your JAXB (JSR-222) provider then you can leverage our #XmlInverseReference extension to map your bi-directional relationship.
You can find a complete example on my blog:
http://blog.bdoughan.com/2013/03/moxys-xmlinversereference-is-now-truly.html
Related
my current code marshalls perfectly, and I get the element I want inside of my resulting XML. i.e. <food>Beef</food>
However, the problem comes when I have to unmarshall this back to a java object. Everything returns fine except the food variable. I originally did not have the XmlElement(required = true) on top, and the food element would always unmarshal back to null. Then, I added the required=true section and I am getting issues with the interface. I did some digging and from what I can gather, jaxb can't really unmarshal into an interface since it doesn't know the concrete type to marshall into.
Current error if this helps:
Can not set FoodInterface field BigPayload.food to
com.sun.org.apache.xerces.internal.dom.ElementNSImpl
My Java classes are as follows:
#XmlSeeAlso({MeatFoods.class, VeggieFoods.class})
#XmlType(name ="BigPayload", propOrder = //stuff goes here
#XmlRootElement(name = foodPayload)
public class BigPayload implements Payload{
#XmlElements({#XmlElement(type = MeatFoods.class),
#XmlElement(type = VeggieFoods.class),
#XmlElement(required = true)})
protected FoodInterface food;
protected Grade grade;
//grade/food setters and getters
}
#XmlTransient //If this isn't here, I get the jaxB cannot handle interfaces and no default constructor error
public interface FoodInterface{ //stuff here}
#XmlType(name = "MeatFoods")
#XmlEnum
public enum MeatFoods implements FoodInterface{
Chicken(1, Chicken)
Beef(2, Beef)
Pork(3, Pork)
int value;
String name;
#Override
public int getValue()
#Override
public String getName()
public static FoodInterface getEnumFromValue(int value){//gets stuff}
public static FoodInterface getEnumFromName(String name){//gets stuff}
}
I just wanted to know if that is correct, and there's no real good way to unmarshall an interface type. Is this true? I saw a lot of other questions were about marshalling interfaces, and the unmarshalling questions did not really get answers to my satisfaction. Any answer is appreciated, and I know this isn't a minimal reproducible example, but I'm more looking for a verbal answer instead of a code fix or anything. Although, if there's anything blatantly wrong in the code please let me know!
For the standard cases JAXB can only use (abstract) classes not interfaces.
Options that i can think of
You can use interfaces with #XmlAdapter. See example: [1]
Use Object for JAXB Bindings and expose the interface with casting. (Maybe add validation logic into the `afterUnmarshal(Unmarshaller u, Object parent). [2]
Bind a private field to #XmlAnyElement and do some further processing in afterUnmarshal(Unmarshaller, Object), add #XmlTransient to the target. See example: [3]
With some creativity there might be some other options. But i think all boil down to bascially: try to get to the "raw" parsing options and fill the interface reference manually.
[1]
public static interface Food {
String name();
}
public enum Veggie implements Food {
SALAD;
}
public static enum Meat implements Food {
CHICKEN;
}
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement
public static class UseInterface {
#XmlJavaTypeAdapter(FoodAdapter.class)
#XmlAttribute
private Food food;
public Food getFood() {
return food;
}
public void setFood(Food food) {
this.food = food;
}
}
public static class FoodAdapter extends XmlAdapter<String, Food> {
#Override
public Food unmarshal(String v) throws Exception {
try {
return Veggie.valueOf(v);
} catch (IllegalArgumentException e) {
}
try {
return Meat.valueOf(v);
} catch (IllegalArgumentException e) {
}
throw new IllegalArgumentException("Unknown Food:" + v);
}
#Override
public String marshal(Food v) throws Exception {
return v.name();
}
}
[2]
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement
public static class UseInterface {
#XmlElement
private Object food;
public Food getFood() {
return (Food) food;
}
public void setFood(Food food) {
this.food = food;
}
public void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
if (food != null && !(food instanceof Food)) {
throw new IllegalArgumentException("food is of wrong type: " + food.getClass().getName());
}
}
}
JAXBContext newInstance = JAXBContext.newInstance(UseInterface.class, Meat.class, Veggie.class);
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><useInterface><food xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"meat\">CHICKEN</food></useInterface>";
newInstance.createUnmarshaller().unmarshal(new StringReader(xml));
[3]
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement
public static class UseInterface {
#XmlAnyElement
private org.w3c.dom.Element foo;
#XmlTransient
private SomeInterface ifc
public void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
NamedNodeMap attributes = foo.getAttributes();
// do something with foo on DOM level to bind the subtree to an interface manually
}
}
I've been reading all the questions on this subject, but none of them relate to my problem. I have these classes (each of them in their own file):
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "Root")
public class Root {
#XmlElements({
#XmlElement(name="Child", type=ChildImpl.class),
#XmlElement(name="Child", type=ChildImpl2.class)
})
protected List<AbstractChild> children;
public List<AbstractChild> getChildren() {
if (children == null) {
children = new ArrayList<AbstractChild>();
}
return this.children;
}
}
#XmlTransient
public abstract class AbstractChild {
#XmlElement(name = "Other", required = true)
protected List<Other> others; // class Other is not important for my question, so I'll skip its implementation details
public List<Other> getOthers() {
if (others == null) {
others = new ArrayList<Other>();
}
return this.others;
}
}
#XmlRootElement(name = "Child")
public class ChildImpl extends AbstractChild {
// custom behavior
}
#XmlRootElement(name = "Child")
public class ChildImpl2 extends AbstractChild {
// different custom behavior
}
And then, I have the class that performs the unmarshalling:
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
result = (Root) jaxbUnmarshaller.unmarshal(new ByteArrayInputStream(fileContent)); // where fileContent is an instance of byte[]
Now, depending on our context, I want the unmarshaller to use a specific implementation of Child for the Root object... but that's where I'm struggling: I have no idea how to signal the unmarshaller to use a specific subclass for Child (in our files, the structure of Root, Child and Other is always the same. However, how we process Child depends on the source folder for each file).
I've tried passing the concrete class when creating the context -just for testing purposes- (e.g. JAXBContext.newInstance(Root.class, ChildImpl.class)), but for some reason, the unmarshaller always resolve to the class entered last in the #XmlElements array (In this case ChildImpl2).
I've also tried removing the #XmlElements annotation, but the unmarshaller doesn't know to process the Version elements since the parent class is abstract (that's also the reason why I added the #XmlTransient annotation; I have no interest in trying to instance AbstractChild)
Any ideas?
Thanks in advance!
If the structure in the xml-files is always the same, having an abstract class AbstractChild makes no sense (in my opinion). The logic should be elsewhere in your code, in a strategy or something like that.
But it is kind of possible:
Have an XmlElement representing the child.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "child")
public class Child {
#XmlElement(name = "name")
private String name;
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
}
Have another Class like MyAbstractChild
public abstract class MyAbstractChild {
private final Child child;
public AbstractChild(final Child child) {
this.child = child;
}
public Child getChild() {
return child;
}
}
And subclasses for each behavior you want:
public class MyChildImpl extends MyAbstractChild {
public MyChildImpl(final Child child) {
super(child);
}
// custom behavior here
}
Then you can implement an XmlAdapter:
public class MyChildImpAdapter extends XmlAdapter<Child, MyAbstractChild> {
private final Class<? extends AbstractChild> implClass;
public MyChildImpAdapter(final Class<? extends MyAbstractChild> implClass){
this.implClass = implClass;
}
#Override
public MyAbstractChild unmarshal(final Child child) throws Exception {
if (MyChildImpl.class.equals(this.implClass)) {
return new MyChildImpl(child);
} else {
return new MyChildImpl2(child);
}
}
#Override
public Child marshal(final MyAbstractChild abstractChild) throws Exception {
return abstractChild.getChild();
}
}
Now you can use the new type MyAbstractChild in your root element:
#XmlJavaTypeAdapter(value = MyChildImpAdapter.class)
protected List<MyAbstractChild> children;
Finally you can train the unmarshaller to use your adapter of choice:
final JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
final Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
jaxbUnmarshaller.setAdapter(MyChildImpAdapter.class, new MyChildImpAdapter(MyChildImpl.class));
final InputStream inputStream = getClass().getResourceAsStream("some.xml");
final Root root = (Root) jaxbUnmarshaller.unmarshal(inputStream);
Now you have your Root-Element with MyChildImpl-Objects in the children.
But as I wrote in the beginning: there should be another option :)
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.
When trying to unmarshall this xml:
<holder>
<name>a</name>
<elements>
<element>
<name>elem</name>
</element>
</elements>
</holder>
I get the error unexpected element (uri:"", local:"element"). Expected elements are <{}link>,<{}totalSize> in the ValidationEventHandler and the tag <elements> (and therefore the elements field in Holder class) is ignored.
When generating the XML both link and totalSize are not outputted as they are nil.
JAVA MODEL
The hierarchy is a bit complex:
(Simplified for the sake of the question)
ElementRoot
abstract ElementRoot has the link member
public abstract class ElementRoot implements Serializable {
protected String link;
#XmlElement(name = "link")
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
}
Wrapper
abstract Wrapper extends ElementRoot and has the totalSize member
public abstract class Wrapper<T> extends ElementRoot {
protected int totalSize;
protected List<T> collection = new ArrayList<>();
#XmlElement
public int getTotalSize() {
return totalSize;
}
public void setTotalSize(int totalSize) {
this.totalSize = totalSize;
}
public abstract List<T> getCollection();
}
Holder
Holder extends ElementRoot
#XmlRootElement(name = "holder")
#XmlType(propOrder = {"name", "elements"})
public class Holder extends ElementRoot {
private String name;
private Elements elements;
// setters and getters not annotated
}
Elements
Elements extends Wrapper and has a collection of Element
import java.util.Collection;
import javax.xml.bind.annotation.*;
#XmlRootElement(name = "elements)
public class Elements extends Wrapper {
#Override
#XmlElement(name="element")
public Collection<Element> getElements() {
return elements;
}
// No setter, to add getElements().add(element)
}
Element
Element extends ElementRoot
#XmlRootElement(name = "element")
#XmlType(propOrder = {"id", "name"})
public class Element extends ElementRoot {
private Integer id;
private String name;
// setters and getters no annotated
}
ENVIRONMENT
I'm using java 7:
JAXB-api 2.2.7
MOXy 2.5.0
There appears to be a bug in EclipseLink JAXB (MOXy) for this use case related to the abstract getCollecion property. We have opened up the following bug that you can use to track our progress on this issue:
http://bugs.eclipse.org/411408
WORK AROUND
Wrapper
We can use #XmlAccessorType(XmlAccessType.NONE) so that only annotated fields/properties will be processed (see: http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html).
import java.util.*;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.NONE)
public abstract class Wrapper<T> extends ElementRoot {
protected int totalSize;
protected List<T> collection = new ArrayList<>();
#XmlElement
public int getTotalSize() {
return totalSize;
}
public void setTotalSize(int totalSize) {
this.totalSize = totalSize;
}
public abstract List<T> getCollection();
}
Elements
Since #XmlAccessorType is inherited by the subclasses we will specify XmlAccessType.PUBLIC to return things to normal. Note: I assume the getElements() method in your question should have been getCollection().
import java.util.*;
import javax.xml.bind.annotation.*;
#XmlRootElement(name = "elements")
#XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
public class Elements extends Wrapper {
#Override
#XmlElement(name="element")
public List<Element> getCollection() {
return collection;
}
// No setter, to add getElements().add(element)
}
I am writing a webservice to maintain a database. I am trying to use JPA (EclipseLink) for the entity classes. However, the database uses natural primary keys and therefore there's potential that an update on the ID fields will fail due to foreign key constraints. Our DBA has provided a function to update the ID fields which will create a new parent record with the updated ID, update the child records to point to the new parent and delete the old parent.
If the ID fields could be updated "normally", I would have a situation like this:
#Entity
#Table(name = "PARENT")
public class Parent implements Serializable
{
private static final long serialVersionUID = 1L;
private String parent;
private String attribute;
private Set<Child> childs;
public Parent()
{
}
#Id
#Column(name = "PARENT")
public String getParent()
{
return this.parent;
}
public void setParent(String parent)
{
this.parent = parent;
}
#Column(name = "ATTRIBUTE")
public String getAttribute()
{
return this.attribute;
}
public void setAttribute(String attribute)
{
this.attribute = attribute;
}
#OneToMany(mappedBy = "parentBean")
public Set<Child> getChilds()
{
return this.childs;
}
public void setChilds(Set<Child> childs)
{
this.childs = childs;
}
}
#Entity
#Table(name = "CHILD")
public class Child implements Serializable
{
private static final long serialVersionUID = 1L;
private String child;
private String attribute;
private Parent parentBean;
public Child()
{
}
#Id
#Column(name = "CHILD")
public String getChild()
{
return this.child;
}
public void setChild(String child)
{
this.child = child;
}
#Column(name = "ATTRIBUTE")
public String getAttribute()
{
return this.attribute;
}
public void setAttribute(String attribute)
{
this.attribute = attribute;
}
#ManyToOne
#JoinColumn(name = "PARENT")
public Parent getParent()
{
return this.parent;
}
public void setParent(Parent parent)
{
this.parent = parent;
}
}
I also have a GenericServiceBean class with a method to call functions:
#Stateless
public class GenericServiceBean implements GenericService
{
#PersistenceContext(unitName = "PersistenceUnit")
EntityManager em;
public GenericServiceBean()
{
// empty
}
#Override
public <T> T create(T t)
{
em.persist(t);
return t;
}
#Override
public <T> void delete(T t)
{
t = em.merge(t);
em.remove(t);
}
#Override
public <T> T update(T t)
{
return em.merge(t);
}
#Override
public <T> T find(Class<T> type, Object id)
{
return em.find(type, id);
}
. . .
#Override
public String executeStoredFunctionWithNamedArguments(String functionName,
LinkedHashMap<String, String> namedArguments)
{
Session session = JpaHelper.getEntityManager(em).getServerSession();
StoredFunctionCall functionCall = new StoredFunctionCall();
functionCall.setProcedureName(functionName);
functionCall.setResult("RESULT", String.class);
for (String key : namedArguments.keySet())
{
functionCall.addNamedArgumentValue(key, namedArguments.get(key));
}
ValueReadQuery query = new ValueReadQuery();
query.setCall(functionCall);
String status = (String)session.executeQuery(query);
return status;
}
}
If I set the ID fields to be not editable:
#Id
#Column(name = "PARENT", udpatable=false)
public String getParent()
{
return this.parent;
}
and call parent.setParent(newParent) will this still update the ID in the entity object? How does this affect any child entities? Will they also be updated (or not)?
Another scenario I don't know how to deal with is where I need to update both the ID and another attribute. Should I call the function which updates (and commits) the ID in the database then make calls to set both the ID and attribute via the normal set* methods and then the persistence context will only commit the attribute change?
Perhaps this is a situation where JPA is not appropriate?
Any advice on this is greatly appreciated.
If I set the ID fields to be not editable (...) and call parent.setParent(newParent) will this still update the ID in the entity object? How does this affect any child entities? Will they also be updated (or not)?
updatable=false means that the column won't be part of the SQL UPDATE statement regardless of what you do at the object level so the Id shouldn't be updated. And I'm also tempted to say that child entities shouldn't be affected, especially since you're not cascading anything.
Another scenario I don't know how to deal with is where I need to update both the ID and another attribute (...)
Well, my understanding is that you'd have to call the function anyway so I would call it first.
Perhaps this is a situation where JPA is not appropriate?
I'm not sure raw SQL would deal better with your situation. Actually, the whole idea of changing primary keys sounds strange if I may.