I have the following class:
class A {
Map<String, String> mapping;
public A() {...}
private Map<String, String> getMapping() {...};
private void setMapping(Map<String, String> mapping) { ... };
}
I need to be able to serialize/deserialize this class in XML with the following representation:
<a>
<entry key="foo" value="bar"/>
<entry key="xbaz" value="xklux"/>
</a>
We use jaxb-intros to configure JAXB for these classes, and I have the following configuration:
<Class name="A">
<XmlRootElement name="a"/>
<Method name="getMapping">
<XmlElement name="mapping"/>
<XmlJavaTypeAdapter value="MappingAdapter"/>
</XmlMethod>
</Class>
Which works but produces:
<a>
<mapping>
<entry key="test" value="a"/>
<entry key="mdx.foo" value="bar"/>
</mapping>
</a>
My question is: how do I get rid of this awful mapping element?
I tried removing the XmlElement element in my JAXB configuration but then I end up with
<a/>
JAXB is not even calling the adapter code.
My second attemps is with another adapter, AAdapter (supposed to handle directly the A object), that I suppose would be configurable this way:
<Class name="A">
<XmlRootElement name="a"/>
<XmlJavaTypeAdapter value="AAdapter"/>
</Class>
But then its marshal() method is not called, and I have no error message from JAXB (which might be due to our JAXB configuration which is another story). And I get the following output:
<a/>
The AAdapter should directly produce the entry elements if it was called.
I saw multiple related posts on how to remove intermediate markup for sub attributes but they seem to be different to my problem since here I want to remove the element for a direct attribute.
So how can I call an adapter for an attribute without putting its result in an element? Or how do I call an adapter directly on the class to serialize?
Thanks in advance for your answers.
Edit: based on this JAXB ticket this seem impossible by design, but if anyone has a workaround it would be great.
Related
In my java(/spring/hibernate) web app, I am contending with XML like this (I've simplified it down a lot for example purposes - I cannot modify the XML as I'm receiving it from a third party - I only control the client code, and client domain objects - there is no XSD or WSDL to represent this XML either):
<?xml version="1.0" encoding="utf-16"?>
<Records count="22321">
<Metadata>
<FieldDefinitions>
<FieldDefinition id="4444" name="name" />
<FieldDefinition id="5555" name="hair_color" />
<FieldDefinition id="6666" name="shoe_size" />
<FieldDefinition id="7777" name="last_comment"/>
<!-- around 100 more of these -->
</FieldDefinitions>
</Metadata>
<!-- Several complex object we don't care about here -->
<Record contentId="88484848475" >
<Field id="4444" type="9">
<Reference id="56765">Joe Bloggs</Reference>
</Field>
<Field id="5555" type="4">
<ListValues>
<ListValue id="290711" displayName="Red">Red</ListValue>
</ListValues>
</Field>
<Field id="6666" type="4">
<ListValues>
<ListValue id="24325" displayName="10">10</ListValue>
</ListValues>
</Field>
<Field id="7777" type="1">
<P>long form text here with escaped XML here too
don't need to process or derefernce the xml here,
just need to get it as string in my pojo<P>
</Field>
</Record>
<Record><!-- another record obj here with same fields --> </Record>
<Record><!-- another record obj here with same fields--> </Record>
<!-- thousands more records in the sameish format -->
</Records>
The XML contains a 'records' element, which contains some metadata, then lots of 'record' elements. Each record element contains lots of 'field' entries.
My goal would be to use JAXB to unmarshall this XML into a large collection of 'record' objects. So I could do something like this:
List<Record> unmarhsalledRecords = this.getRecordsFromXML(stringOfXmlShownAbove)
where each record would look like this:
public class Record {
private String name;
private String hairColor;
private String shoeSize;
private String lastComment;
//lots more fields
//getters and setters for these fields
}
However, I've never needed to dereference field names in jaxb - is that even possible with jaxb - or do I need to write some messy/hard to maintain code with a stax parser?
None of the examples I can find online touch on anything like this - any help would be greatly appreciated.
Thank you!
I don't think jaxb supports complex mapping logic like. A couple of options that I can think of.
Transform the xml using freemarker or xslt (I hate xslt) to an xml format that matches your desired model before parsing with jaxb
Eg
<Records>
<Record>
<Name>Joe Bloggs</Name>
<HairColour>Red</HairColour>
...
</Record>
</Records>
Parse the xml as is and write an adapter wrapper in the java layer which adapts from the inbound jaxb objects to your more "user friendly" model. The adapter layer could call into the jaxb objects under the hood so you could later serialize back to xml after changes
I am working on converting a large MyBatis2 map to a MyBatis3 map, and have run into a bit of an issue where I have a resultMap with multiple result elements using the same property attribute (and the class is generated from a WSDL outside of my control):
<resultMap id="blah" class="someWsdlGeneratedClass">
<result property="addressLine"
resultMap="addressLineOneListMap"
javaType="java.util.List" />
<result property="addressLine"
resultMap="addressLineTwoListMap"
javaType="java.util.List" />
</resultMap>
<resultMap id="addressLineXListMap" class="string">
<!-- Result maps are the same except for column -->
<result property="addressLine" column="COLUMN_X" />
</resultMap>
Notice that both properties are "addressLine".
This works fine for Mybatis2. However, if I try to use the same pattern for MyBatis3, I get an IllegalArgumentException: Result Maps collection already contains value for Mapper.mapper_resultMap[blah]_collection[addressLine]
<resultMap id="blah" type="someWsdlGeneratedClass">
<collection property="addressLine"
resultMap="addressLineOneListMap"
javaType="java.util.List" />
<collection property="addressLine"
resultMap="addressLineTwoListMap"
javaType="java.util.List" />
</resultMap>
I'd like to avoid writing a wrapper around the generated class in a Dto object, if possible, as that would result in a major refactoring effort in the project. Is there something I can add in the map itself?
You can add a 2nd setter (setAddressLine2) to your generated dto.
In which your code for it can just add to addressLine. ex:
void setAddressLine2(final List<Address> addressLine2) {
address.addAll(addressLine2);
}
If that's not possible you can try changing your query to return a union of the 2 columns
Without knowing your exact query it would look something like:
SELECT foo, addressLine1 as Address
FROM bar
UNION
SELECT foo, addressLine2 as Address
FROM bar
If that isn't possible then you need to create a test project and create an issue on https://github.com/mybatis/mybatis-3 and request a feature.
That option is probably best anyways as I'm not sure you are using it correctly. It seems that your 2nd example (using collection) is correct (conceptually at least. you still can't map to the same property using it) but the first won't behave as you explained it?
I like to add prefix for attribute while marshaling using castors.
I would like to get result as like below
<ThesaurusConcept dc:identifier="C268">
<ScopeNote xml:lang="en">
<LexicalValue>index heading is Atomic absorption spectroscopy</LexicalValue>
</ScopeNote>
</ThesaurusConcept>
but I am getting
<ThesaurusConcept identifier="C621">
<ScopeNote lang="en">
<LexicalValue>index heading is Atomic absorption spectroscopy</LexicalValue>
</ScopeNote>
</ThesaurusConcept>
I got an answer for my question
we need to add the following in mapping.xml file
<mapping xmlns:dc="http://purl.org/dc/elements/1.1/">
<bind-xml name="dc:identifier" node="attribute" ></bind-xml>
and also we need to set namespace by using following code.
Marshaller casreactmp = new Marshaller(handler);
casreactmp.setNamespaceMapping("dc", "http://purl.org/dc/elements/1.1/");
I'm using the Simple XML Framework for parsing XML files.
From a server i receive a XML-File what looks like this:
<Objects>
<Object type="A">
<name></name>
<color></color>
</Object>
<Object type="B">
<shape></shape>
<weight></weight>
</Object>
<Objects>
I have an interface (or superclass) Object and two subclasses A and B
Is it possible to de-serialize this XML-Document?
I saw in the Tutorial that there is a possibility to differentiate between subclasses with an class-attribute, but unfortunately this is not possible for me. Is there a way to chose that the framework chooses the right sub-class on the base of the type attribute?
I can't use another Framework (like JAXB) because i use Android..
Simple XML can do that too if you are willing to make one minor change to your XML. So in your example, you could change that xml to look like this:
<Objects>
<A>
<name></name>
<color></color>
</A>
<B>
<shape></shape>
<weight></weight>
</B>
<Objects>
And then you could have the following java:
#ElementListUnion({
#ElementList(entry = "A", inline = true, type = A.class),
#ElementList(entry = "B", inline = true, type = B.class)
}
private List<BaseClass> objects;
And that is all that there really is to it. Though I do not think that it can be done based on an Attribute. I could be wrong though, you might want to read the docs for that one.
This'll be tricky to do if you can't use the class attribute, like so:
<Objects>
<Object class="ObjectA">
<name></name>
<color></color>
</Object>
<Object class="ObjectB">
<shape></shape>
<weight></weight>
</Object>
<Objects>
Why replace your type="A" and type="B" attributes with classes, using a regular expression, before feeding it to the Simple XML deserializer? For instance:
xml = xml.replaceAll("type=\"([A-Za-z0-9_]+)\", "class=\"$1\"");
I was able to use this trick parsing XML generated by .NET's XML serializer, which uses the attribute xsi:type to indicate the specific class type in polymorphic lists such as this one.
About Apache XmlBeans. I use AnyType in scheme definition (xsd:anyType) as element in complex type.
Example:
<request xmlns="">
<xml>
<input1>
<string>str</string>
</input1>
</xml>
</request>
in java code
final ProcessRequest processRequest = requestDocument.addNewRequest();
XmlObject xml = processRequest.addNewXml();
xml.changeType(operationType.type);
xml.set(operationType);
and i want to see
<xml xsd:type="*opeation1NSPrefix*:*operation1Type*>
...
</xml>
but i see only <xml/>. What i doing wrong?
stupid mistake: operation1 define as anonymous type <element><complexType>..</></> in wsdl. when i define "<element type=".."/><complexType name=".."/> the problem disappeared