I am having an issue with exporting a custom hashmap function to xml. The layout of my project is as follows. The package adt contains the following classes:
class HashMap implements Map<K,V>
A custom hashmap implementation, pretty much identical to java.util.HashMap. (Note, same errors exist when I use java.util.HashMap)
class Database extends HashMap <String,Table>
class Table extends HashMap <Object, Row>
(Note: The key of type Object is always a string in my implementation)
class Row extends HashMap <String, Object>
(Object is of type String, boolean, or int)
I am trying to export a table to an xml file, and eventually import it again but I haven't gotten that far. Here is the function which I use to export it:
private Response xml(Table table, FileWriter file) {
JAXBContext jaxbContext;
Marshaller jaxbMarshaller;
try {
jaxbContext = JAXBContext.newInstance(HashMap.class);
jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(table, file);
}catch (JAXBException e) {
e.printStackTrace(System.out);
return new Response(false,"Export - JAXBException.",null);
}//catch
return new Response(true,"Export - Successfully wrote table to file.",null);
}//xml
Also note...
- I can export flawlessly using JsonObjectBuilder from javax.json.* to a json file
- It is required to use the javax.xml library
- I really don't know what I'm doing
It returns the code:
?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<hashMap/>
The table which I am trying to export does have data which is not represented in the XML output. Right now, the HashMap class has #XmlRootElement at the top. That is the only XML annotation in any class.
I also receive a NullPointerException when I change this line
jaxbContext = JAXBContext.newInstance(HashMap.class);
to this:
jaxbContext = JAXBContext.newInstance(Table.class);
The exception is as follows:
Exception in thread "main" java.lang.NullPointerException
at com.sun.xml.internal.bind.v2.runtime.property.SingleMapNodeProperty.serializeBody(SingleMapNodeProperty.java:252)
at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:345)
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:578)
at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:326)
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:479)
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:308)
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:236)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:95)
at driver.DExport.xml(DExport.java:99)
at driver.DExport.execute(DExport.java:59)
at core.Server.interpret(Server.java:57)
at core.Console.prompt(Console.java:56)
at core.Console.main(Console.java:37)
After much trial and error, it so turns out that I needed to create a list of Row extends HashMap<String,Object> types. I guess the fact that there was nested hashmapping (Table extends Hashmap<Object,Row extends Hashmap<String,Object>> screwed it up. Now, my Row class contains #XmlRootElement, and I made my Tuple(known as Entry in java.util.Hashmap) static, with the get methods for key and val having the #XmlElement annotation. Now I must export in a loop. Pretty sure this is the wrong way to do it but it works(kinda)...
jaxbContext = JAXBContext.newInstance(Row.class);
jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
for (int i = 0; i<rows.size(); i++) {
jaxbMarshaller.marshal(rows.get(i), file);
}//for
and the output...
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<row>
<Tuple>
<key xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">str</key>
<val xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">goodbye</val>
</Tuple>
<Tuple>
<key xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">bool</key>
<val xsi:type="xs:boolean" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">false</val>
</Tuple>
</row>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<row>
<Tuple>
<key xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">str</key>
<val xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">hello</val>
</Tuple>
<Tuple>
<key xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">bool</key>
<val xsi:type="xs:boolean" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">true</val>
</Tuple>
</row>
Related
I'm working with the ECCP protocol in order to integrate my CRM with the Elastix Call Center Module. The protocol uses a XML structure defined as follows:
<request id="1">
<request_type> <!-- this will be mapped to the Java request class -->
<attributes>
</attributes>
</request_type>
</request>
and
<response id="1">
<response_type> <!-- this will be mapped to the Java response class -->
<attributes>
</attributes>
</response_type>
</response>
I'm using JAX-B to map XML to Java classes but the problem is that I have to put the JAX-B generated XML inside a <request></request> XML every request and extract the content from <response></response> in every response because the ECCP protocol defines that every request and response needs to nested to their respective elements.
Here's the code I'm using to do that:
document = createDocument();
Element requestWrapper = document.createElement("request");
requestWrapper.setAttribute("id", String.valueOf(wrapped.getId()));
document.appendChild(requestWrapper);
JAXBContext jc = JAXBContext.newInstance(wrapped.getClass());
Marshaller marshaller = jc.createMarshaller();
marshaller.marshal(wrapped, requestWrapper);
Exemplifying:
One of ECCP's protocol operation is JAX-B-mapped into a class like this (getters and setters were omitted):
#XmlRootElement(name = "loginagent")
#XmlAccessorType(XmlAccessType.FIELD)
public class EccpLoginAgentRequest implements IEccpRequest {
#XmlElement(name = "agent_number")
private String agentNumber;
#XmlElement(name = "password")
private String password;
}
And JAX-B outputs the following:
<loginagent>
<agent_number>username</agent_number>
<password>password</password>
</loginagent>
But what the ECCP's protocol requires is:
<request id="1"> <!-- id is an auto-increment number to identify the request -->
<loginagent>
<username>username</username>
<password>password</password>
</loginagent>
</request>
The question is: is there any other way to achieve in any other better way?
Thank you.
You can probably check out the #XmlSeeAlso annotation which will help you wrap the same content both for request and response. For the inner part you can create the separate class and map all the fields appropriately. I hope this helps you a little bit.
EDIT:
Sorry for the long response time. You need to create a wrapper class with the inner structure defined as an #XmlElement. Here's the way to achieve that XML structure:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "request")
public class RequestWrapper {
#XmlElement(name = "loginagent", required = true)
protected EccpLoginAgentRequest loginagent;
public EccpLoginAgentRequest getLoginagent() {
return loginagent;
}
public void setLoginagent(EccpLoginAgentRequest loginagent) {
this.loginagent = loginagent;
}
}
And here's the EccpLoginAgentRequest structure:
#XmlAccessorType(XmlAccessType.FIELD)
public class EccpLoginAgentRequest {
#XmlElement(name = "agent_number")
private String agentNumber;
#XmlElement(name = "password")
private String password;
// getters and setters omitted
}
So in result, you can print the XML you want like that:
JAXBContext jaxbContext = JAXBContext.newInstance(Wrapper.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
EccpLoginAgentRequest request = new EccpLoginAgentRequest();
request.setAgentNumber("1");
request.setPassword("pass");
Wrapper wrapper = new Wrapper();
wrapper.setLoginagent(request);
jaxbMarshaller.marshal(wrapper, System.out);
It will give you the following output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<request>
<loginagent>
<agent_number>1</agent_number>
<password>pass</password>
</loginagent>
</request>
I found a way to solve this in this post: XML element with attribute and content using JAXB
So I've mapped a EccpRequestWrapper object as the following:
#XmlRootElement(name = "request")
public class EccpRequestWrapper {
#XmlAttribute
private Long id;
#XmlAnyElement
private IEccpRequest request;
}
and then my request JAX-B outputs my request the way ECCP protocol requires.
The #XmlAttribute and #XmlAnyElement annotation did the trick.
<request id="1">
<login>
<username>user</username>
<password>****</password>
</login>
</request>
A good JAXB guide can be found here https://jaxb.java.net/guide/Mapping_interfaces.html
I've got a class that wraps a generic list. When I put a Map in that generic wrapped list, the JAXB output is not what I expect. Items are shown, but their contents isn't.
To elaborate:
A simplified version of my class:
#XmlRootElement #XmlSeeAlso({HashMap.class, ArrayList.class, Dummy.class})
public static class TargetClass<T> {
public List<T> wrapped = new ArrayList<>();
}
When the wrapped list contains a Map, the result is not what I'd expect. Using:
#GET #Produces(MediaType.APPLICATION_XML)
public TargetClass<Map<String, String>> thisIsWhatIWant() {
Map<String, String> map = new HashMap<>();
map.put("hello", "world");
TargetClass<Map<String, String>> result = new TargetClass<>();
result.wrapped.add(map);
result.wrapped.add(map);
return result;
}
I get:
<targetClass>
<wrapped xsi:type="hashMap"/>
<wrapped xsi:type="hashMap"/>
</targetClass>
But I was hoping for
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<targetClass>
<wrapped>
<entry>
<key>hello</key>
<value>world</value>
</entry>
</wrapped>
<wrapped>
<entry>
<key>hello</key>
<value>world</value>
</entry>
</wrapped>
</targetClass>
There is a lot of good JAXB answers on here (thanks #blaise-doughan and others), but as far as I could find, not on this one.
Other things I tried:
Lists and Maps are serialized like I expect if I use them directly
#GET #Path("baseTest") #Produces(MediaType.APPLICATION_XML)
public BaseTest thisWorksAsExpected() {
BaseTest baseTest = new BaseTest();
baseTest.list.add("item");
baseTest.list.add("item");
baseTest.map.put("hello", "world");
baseTest.map.put("foo", "bar");
return baseTest;
}
output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<baseTest>
<list>item</list>
<list>item</list>
<map>
<entry>
<key>hello</key>
<value>world</value>
</entry>
<entry>
<key>foo</key>
<value>bar</value>
</entry>
</map>
</baseTest>
TargetClass works as expected when I drop an XMLRootElement in there:
#XmlRootElement
public static class Dummy {
public String a = "a";
public String b = "b";
}
#GET #Path("other") #Produces(MediaType.APPLICATION_XML)
public TargetClass<Dummy> other() {
TargetClass<Dummy> result = new TargetClass<>();
result.wrapped.add(new Dummy());
result.wrapped.add(new Dummy());
return result;
}
output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<targetClass>
<wrapped xsi:type="dummy">
<a>a</a>
<b>b</b>
</wrapped>
<wrapped xsi:type="dummy">
<a>a</a>
<b>b</b>
</wrapped>
</targetClass>
Any clue?
Groeten,
Friso
One of my client to integrate provide an XML with attribute name "_1", "_2" ... etc.
e.g.
<element _1="attr1" _2="attr2">
using JAXB to generate the class, the getter method of the attribute will be get1() and get2()
However in my JSP pages, using JSTL and EL, sure I cannot access the value through
${variable.1}
How can I access the value using EL correctly?
You could use an external binding file to rename the property generate by JAXB:
schema.xsd
Below is a sample XML schema based on your post:
<?xml version="1.0" encoding="UTF-8"?>
<schema
xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org"
xmlns:tns="http://www.example.org"
elementFormDefault="qualified">
<element name="element1">
<complexType>
<attribute name="_1" type="string" />
<attribute name="_2" type="string" />
</complexType>
</element>
</schema>
binding.xml
An external binding file is used to customize how Java classes are generated from the XML schema. Below we'll use an external binding file to rename the generated properties.
<jaxb:bindings
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jaxb:bindings schemaLocation="schema.xsd">
<jaxb:bindings node="//xsd:attribute[#name='_1']">
<jaxb:property name="one"/>
</jaxb:bindings>
<jaxb:bindings node="//xsd:attribute[#name='_2']">
<jaxb:property name="two"/>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
XJC Call
Below is an example of how you reference the binding file when using the XJC tool.
xjc -b binding.xml schema.xsd
Element1
Below is what the generated class will look like:
package forum12259754;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "")
#XmlRootElement(name = "element1")
public class Element1 {
#XmlAttribute(name = "_1")
protected String one;
#XmlAttribute(name = "_2")
protected String two;
public String getOne() {
return one;
}
public void setOne(String value) {
this.one = value;
}
public String getTwo() {
return two;
}
public void setTwo(String value) {
this.two = value;
}
}
Use this notation:
${variable.["1"]}
I'm using a POJO object with XmlType for a custom XML adapter I built for marshaling a map of strings. I'm having issues however, with getting it to allow me to use null values properly. I was able to get it to work, but I'm not happy with the XML it is generating.
This is what I'm currently using that I would like to work, but as you can see in an sample XML result, it is not including the proper xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" value
#XmlType(name="element")
public class RestMapElements {
#XmlAttribute(name="name")
public String key;
#XmlValue
public String value;
public RestMapElements(String key, String value) {
this.key = key;
this.value = value;
}
}
The resulting XML (slimmed to relevant data).
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
...
<element-list>
<item name="activated_date">2012-03-29 11:34:14.323</item>
<item name="some_null_value"/>
</element-list>
...
However, I was able to get it to work with this, I'm just not happy with the XML having to add an additional "value" tag inside of the item tag to get it to work. (side note, why is it naming it item instead of element like I tried to specify in the XmlType name declaration?)
#XmlType(name="element")
public class RestMapElements {
#XmlAttribute(name="name")
public String key;
#XmlElement(nillable = true)
public String value;
public RestMapElements(String key, String value) {
this.key = key;
this.value = value;
}
}
Again, the resulting XML (slimmed to relevant data).
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
...
<element-list>
<item name="activated_date"><value>2012-03-29 11:34:14.323</value></item>
<item name="some_null_value"><value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/></item>
</element-list>
...
Really, I can use the second as it works to solve my issue. I'm just wanting to use this as a learning experience to see if JAXB using annotations will allow be to bend this to what I'm looking for without having to add that additional value tag underneath an item tag just so I can support null values. Right now, when it unmarshals in the first example, I end up getting empty strings instead of null. In the second example, I get the null value I was expecting.
FYI: I'm currently using Jersey 1.11
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
You could use MOXy's #XmlNullPolicy extension to map this use case:
RestMapElements
package forum10415075;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
#XmlType(name="element")
public class RestMapElements {
#XmlAttribute(name="name")
public String key;
#XmlValue
#XmlNullPolicy(nullRepresentationForXml=XmlMarshalNullRepresentation.XSI_NIL)
public String value;
}
Root
package forum10415075;
import java.util.*;
import javax.xml.bind.annotation.*;
#XmlRootElement
public class Root {
#XmlElementWrapper(name="element-list")
#XmlElement(name="item")
public List<RestMapElements> items = new ArrayList<RestMapElements>();
}
jaxb.properties
To use MOXy as your JAXB (JSR-222) provider you need to add a file called jaxb.properties in the same package as your domain model with the following content:
javax.xml.bind.context.factory = org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
package forum10415075;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum10415075/input.xml");
Root root = (Root) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8"?>
<root>
<element-list>
<item name="activated_date">2012-03-29 11:34:14.323</item>
<item name="some_null_value" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</element-list>
</root>
Note
If you are using Jersey in GlassFish 3.1.2 MOXy or WebLogic 12.1.1 is already included:
http://blog.bdoughan.com/2012/02/glassfish-312-is-full-of-moxy.html
http://blog.bdoughan.com/2011/12/eclipselink-moxy-is-jaxb-provider-in.html
I see your problem. An item element with xsi:nil="true" will be generated only by setting the corresponding RestMapElements entry in your ArrayList (or whatever) to null, losing the attribute. I think there isn't much of a solution to this.
One option would be to use your marshalling from the beginning of your post and unmarshal using the following:
If you're doing something like this:
#XmlElementWrapper(name="element-list")
#XmlElement(name="item")
public ArrayList<RestMapElements> list;
You can use a XmlAdapter to check if the value is an empty String and set it to null if it is:
#XmlElementWrapper(name="element-list")
#XmlElement(name="item")
#XmlJavaTypeAdapter(ItemAdapter.class)
public ArrayList<RestMapElements> list;
And ItemAdapter:
public class ItemAdapter extends XmlAdapter<RestMapElements, RestMapElements> {
#Override
public RestMapElements unmarshal(RestMapElements v) throws Exception {
if (v.value.equals("")) v.value = null;
return v;
}
}
Although this is still inelegant imho.
If you want to generate the proper xsi:nil="true" item elements, this is obviously not what you want though.
Good luck.
I am trying to map a POJO to an xml. Now the POJO consists of some attributes which are basic String/Integer etc and some which are other POJO classes. The xml mapping file that I am attempting to create, I want an xml element at the top level to be populated with a java attribute that is 2 levels deep.
for example, if I have 2 java class
`
class classA{
private ClassB var1
private String var2
}
class classB{
private ClassC var3;
}
class classC{
private String var4;
}
Now my xml mapping looks like
CruiseLine Mapping
<class name="ClassA"
auto-complete="false"
>
<map-to xml="Sample" />
<field name="var2">
<bind-xml node="attribute" name="var2" />
</field>
<field name="var4 from classC">
<I want a mapping for the var4 from classC to appear here. How do I do that ?>
</class>
`
As you see, I want the mapping for var4 from classC in the xml element Sample. I want it to be an element of the sample element.
`
<Sample var2="value">
<data var4="var4 value">
</Sample>
`
Help appreciated !
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
Blaise : I have not used EclipseLink before, however I think I can
move out of castor if it is relatively simple to adopt EclipseLink ?
Its just that the entire project has been using Castor so it would be
more consistent. However, could you please elaborate on Eclipselink.
Thanks. – TYS
EclipseLink MOXy is a JAXB (JSR-222) implementation. Looking at your question, this model can be mapped to the desired XML using any JAXB implementation as follows:
ClassA
package forum9994762;
import javax.xml.bind.annotation.*;
#XmlRootElement(name="Sample")
#XmlAccessorType(XmlAccessType.FIELD)
public class ClassA {
#XmlElement(name="data")
private ClassB var1;
#XmlAttribute
private String var2;
}
ClassB
package forum9994762;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class ClassB {
#XmlAttribute(name="var4")
private ClassC var3;
}
ClassC
package forum9994762;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class ClassC {
#XmlValue
private String var4;
}
Demo
package forum9994762;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(ClassA.class);
File xml = new File("src/forum9994762/input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
ClassA classA = (ClassA) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(classA, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Sample var2="value">
<data var4="var4 value"/>
</Sample>
Mapping File
As a Castor user, you may prefer representing your metadata as an external mapping file. EclipseLink MOXy offers such an extension:
binding.xml
<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum9994762"
xml-accessor-type="FIELD">
<java-types>
<java-type name="ClassA">
<xml-root-element name="Sample"/>
<java-attributes>
<xml-element java-attribute="var1" name="data"/>
<xml-attribute java-attribute="var2"/>
</java-attributes>
</java-type>
<java-type name="ClassB">
<java-attributes>
<xml-attribute java-attribute="var3" name="var4"/>
</java-attributes>
</java-type>
<java-type name="ClassC">
<java-attributes>
<xml-value java-attribute="var4"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Demo
package forum9994762;
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, "forum9994762/binding.xml");
JAXBContext jc = JAXBContext.newInstance("forum9994762", ClassA.class.getClassLoader(), properties);
File xml = new File("src/forum9994762/input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
ClassA classA = (ClassA) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(classA, System.out);
}
}
For More Infomation
http://blog.bdoughan.com/2010/12/extending-jaxb-representing-annotations.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
If you use auto-complete=false in your mapping.xml file for ClassA <class name="ClassA" auto-complete="false" > then you must tell Castor marshaller how to map ClassB and ClassC individually.
Including these two lines may help you getting started:
<class name="ClassB" auto-complete="true">
<map-to xml="class-B" />
</class>
<class name="ClassC" auto-complete="true">
<map-to xml="class-C" />
</class>
But since var4 is a member of ClassC but not ClassB, it will be one level deep inside your xml output hierarchy.