Partial Unmarshalling with JAXB gives IllegalAnnotationexceptions - jaxb

when partially unmarshalling an XML, I am receiving the following error message:
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 6 counts of IllegalAnnotationExceptions
Property id is present but not specified in #XmlType.propOrder
this problem is related to the following location:
at public java.lang.String xmlFields.Example.getId()
at xmlFields.Example
Property text is present but not specified in #XmlType.propOrder
this problem is related to the following location:
at public java.lang.String xmlFields.Example.getText()
at xmlFields.Example
Property type is present but not specified in #XmlType.propOrder
this problem is related to the following location:
at public java.lang.String xmlFields.Example.getType()
at xmlFields.Example
Property ID appears in #XmlType.propOrder, but no such property exists. Maybe you meant id?
this problem is related to the following location:
at xmlFields.Example
Property Text appears in #XmlType.propOrder, but no such property exists. Maybe you meant text?
this problem is related to the following location:
at xmlFields.Example
Property Type appears in #XmlType.propOrder, but no such property exists. Maybe you meant type?
this problem is related to the following location:
at xmlFields.Example
at com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:91)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:451)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:283)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:126)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1148)
at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:130)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:248)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:235)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:445)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:637)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:584)
at extractFromXML.ReadFromXML.convertToJavaObject(ReadFromXML.java:72)
at extractFromXML.ReadFromXML.main(ReadFromXML.java:97)
I have the follwing implementation (extracting only a part of the xml seem to work):
#XmlRootElement
#XmlType(propOrder={"ID", "Text", "Type"})
public class Example {
private String id;
private String text;
public Example() {
super();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
private String type;
}
And this is the part of the xml file:
......<ExampleOptions><Example> <ID>ETZH8</ID> <Text>hello</Text> <Type>VAR</Type> </Example></ExampleOptions>.......
Any ideas?
Thanks
UPDATE #1
I adapted the suggestions by Blaise, but still getting only null values:
Example [id=null, text=null, type=null, getId()=null, getText()=null, getType()=null, getClass()=class xmlFields.Example, hashCode()=18467372, toString()=xmlFields.Example#119ca2c]
UPDATE #2
This is my current code:
#XmlRootElement
#XmlType(propOrder={"id", "text", "type"})
public class Example {
private String id;
private String text;
private String type;
public Example() {
super();
}
#XmlElement(name="ID")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#XmlElement(name="Text")
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
#XmlElement(name="Type")
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
I can't publish the whole XML. It is a nested XML file.
UPDATE #3
The problem is, I only try to extract a part of my xml. Therefore, I have the following main function:
public static void main(String[] args) throws Exception {
try {
XMLInputFactory xif = XMLInputFactory.newFactory();
StreamSource xml = new StreamSource(POI_XML);
XMLStreamReader xsr = xif.createXMLStreamReader(xml);
xsr.nextTag();
while(xsr.hasNext()) {
if(xsr.isStartElement() && xsr.getLocalName().equals("Example")) {
break;
}
xsr.next();
}
JAXBElement<Example> jb;
try {
JAXBContext context = JAXBContext.newInstance(Example.class);
Unmarshaller um = context.createUnmarshaller();
jb = um.unmarshal(xsr, Example.class);
xsr.close();
Example stations = jb.getValue();
System.out.println(stations.toString());
} catch (JAXBException e) {
e.printStackTrace();
}
} catch (FactoryConfigurationError e) {
e.printStackTrace();
} catch (XMLStreamException e) {
e.printStackTrace();
}
}
Moreover, I just tried to extract just an example of one deep path in the nested XML. It looks more than:
<ExampleOptions><Example> <ID>ETZH8</ID> <Text>hello</Text> <Type>VAR</Type> </Example></ExampleOptions><ConnectionCount>1</ConnectionCount><Info>abc</Info>.....
UPDATE #4
I just checked the marshalling example with the following error message:
Exception in thread "main" javax.xml.bind.UnmarshalException
- with linked exception:
[org.xml.sax.SAXParseException; systemId: file:///D:/proj/ConvertXMLToPostgres/input2.xml; lineNumber: 1; columnNumber: 39; Vorzeitiges Dateiende.]

The propOrder is based on the field/property names and not the elements that they are mapped to. You just need to change your propOrder:
#XmlType(propOrder={"id", "text", "type"})
The stack trace also points you in this direction:
Property ID appears in #XmlType.propOrder, but no such property exists. Maybe you meant id?
this problem is related to the following location:
at xmlFields.Example
Property Text appears in #XmlType.propOrder, but no such property exists. Maybe you meant text?
this problem is related to the following location:
at xmlFields.Example
Property Type appears in #XmlType.propOrder, but no such property exists. Maybe you meant type?
this problem is related to the following location:
at xmlFields.Example
For More Information
I have written more about this on my blog:
http://blog.bdoughan.com/2012/02/jaxbs-xmltype-and-proporder.html
UPDATE #1
Thanks. I changed the code, but I am getting null values.
The element names in your XML don't match the default names that JAXB derives from your property names, so you will need to override it with an #XmlElement annotation.
#XmlElement("ID")
public String getId() {
return id;
}
Debugging Tip:
When you run into an issue when unmarshalling, try populating your object model and marshalling it to XML to see what XML is expected.
UPDATE #2
Demo
When I run the following against your updated Example class everything works for me. Does it work for you as well?
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Example.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StreamSource source = new StreamSource("input.xml");
JAXBElement<Example> result = unmarshaller.unmarshal(source, Example.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(result, System.out);
}
}
Input/Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Example>
<ID>ETZH8</ID>
<Text>hello</Text>
<Type>VAR</Type>
</Example>
UPDATE #3
When I run the Java code from your UPDATE #3 against the model from your UPDATE #2 with the following XML everything works:
<ExampleOptions><Example> <ID>ETZH8</ID> <Text>hello</Text> <Type>VAR</Type> </Example></ExampleOptions>
Can you update your code in UPDATE #3 to include System.out.println(xsr.getNamespaceURI()); to see if there are any namespaces in play?
while(xsr.hasNext()) {
if(xsr.isStartElement() && xsr.getLocalName().equals("Example")) {
System.out.println(xsr.getNamespaceURI());
break;
}
xsr.next();
}

Related

How to persist UserData of Element in JAXB Unmarshal?

I unmarshal the Document to object as below.
Before that, when parsing XML, use setUserData to store location information for each element.
class MyJaxbAdapter extends XmlAdapter<Object, SubObject> {}
#Override
public UnattendComponent unmarshal(Object v) throws Exception {
Node node = (Node) v; // ElementNSImpl; It's probably a newly created object. Because It is different from the document object given by ownerDocument as SAXSource.
node.getUserData(...) // return NULL
}
}
Document document = ...;
unmarshaller.setAdapter(new MyJaxbAdapter());
MyXMLObject object = unmarshaller.unmarshal(new DOMSource(document), MyXMLObject.class).getValue();
But I can't get UserData inside XmlAdapter's unmarshal method. Is there any way to persist UserData?
Locator information is stored in the properties of Element as shown below.
#Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
Element el = document.createElementNS(usedNamespaceUri, qName);
// ...
el.setUserData(
ElementUserData.class.getName(),
ElementUserData.builder()
.lineNumber(locator.getLineNumber())
.columnNumber(locator.getColumnNumber())
.build(),
null);
}
I need the Locator information (UserData) stored by the above code in the unmarshal of the XmlAdapter.
However, there is no userdata in the node passed as an argument to unmarshal .
Sample Code:
https://github.com/joseph-jclab/jaxb-question-01
Not entirely sure if this is something you are looking for but providing it as a reference so you might get some idea to proceed further:
Sample XML:
<root>
<name>Batman</name>
<year>2008</year>
</root>
Root.class:
#XmlRootElement(name = "root")
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
private String name;
private String year;
#XmlJavaTypeAdapter(CustomAdapter.class)
private String after;
private void afterUnmarshal(Unmarshaller m, Object parent) {
after = name;
}
}
CustomAdapter.class:
public class CustomAdapter extends XmlAdapter<String, String> {
#Override
public String unmarshal(String v) throws Exception {
System.out.println("Within Unmarshal : " + v);
return null;
}
#Override
public String marshal(String v) throws Exception {
System.out.println("Within Marshal : " + v);
return null;
}
}
SampleMain.class:
public class SampleMain {
public static void main(String[] args) throws XMLStreamException, JAXBException {
final InputStream inputStream = Unmarshalling.class.getClassLoader().getResourceAsStream("sample.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(Root.class).createUnmarshaller();
unmarshaller.setAdapter(new CustomAdapter());
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(name=Batman, year=2008, after=Batman)
Within Marshal : Batman
<root>
<name>Batman</name>
<year>2008</year>
</root>

Is there a way for JAXB to give a warning about this... overridden properties in subclasses?

I ran into an interesting JAXB issue that had me puzzled for a while, since no errors were produced, just wasn't seeing the output I expected.
We have several classes that all extends a Base class.
At one point I introduced an object property into the base class, that also happened to be a property defined in just ONE of the subclasses. This caused any setter of this property from ANY subclasses (outside the one with that property overridden) to have this property completely ignored in the XML output.
For example:
#XmlRootElement(name = "animal")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlSeeAlso({Dog.class, Fish.class})
public class Animal {
protected String movement;
....
}
#XmlRootElement(name = "dog")
#XmlSeeAlso({Animal.class})
#XmlAccessorType(XmlAccessType.FIELD)
public class Dog extends Animal {
private String breed;
protected String movement;
....
}
#XmlRootElement(name = "fish")
#XmlSeeAlso({Animal.class})
#XmlAccessorType(XmlAccessType.FIELD)
public class Fish extends Animal {
private String scaleType;
....
}
public static void main(String[] args) {
Dog dog = new Dog();
dog.setBreed("lab");
dog.setMovement("walks");
String xml = AnimalJaxb.toXml(dog);
System.out.println("dog = "+xml);
Fish fish = new Fish();
fish.setMovement("swims"); //WILL NOT SHOW UP IN XML!
fish.setScaleType("normal");
String xml = AnimalJaxb.toXml(fish);
System.out.println("fish = "+xml);
//to and from XML looks like...
public static <T> T fromXml(String xml, Class<T> clazz) throws Exception {
ByteArrayInputStream input = null;
Unmarshaller u = null;
try {
input = new ByteArrayInputStream(xml.getBytes());
JAXBContext jc = JAXBContext.newInstance(clazz);
u = jc.createUnmarshaller();
} catch (Exception e) {
throw e;
} finally {
input.close();
}
return (T) u.unmarshal(input);
}
public static String toXml(Object obj) throws Exception {
StringWriter sw = new StringWriter();
try {
JAXBContext context = JAXBContext.newInstance(obj.getClass());
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(obj, sw);
return sw.toString();
} catch (Exception e) {
throw e;
} finally {
sw.close();
}
}
When the above runs. The "movement" property on Fish will NOT be in the XML. To fix this, I need to remove the overridden movement property in the Dog class.
What's frustrating is JAXB doesn't throw any errors or complain. The only way it will complain is if I make the base class (Animal) abstract and mark it #XmlTransient, afterwhich JAXB will complain about having "two properties with the same name."

#XmlPath(".") conflicts with #XmlAdapter

having this Jaxb Xml definition, i try to remove the Map Elements Wrapper by adding #XmlPath(".") but it cause exception during the unmarchaling
#XmlRootElement
public abstract class ViewElement{
#XmlJavaTypeAdapter(value=EventAdapter.class)
public Map<Event, String> getEvents() {
}
private transient Class entityType;
public Class getEntityType() {
return entityType;
}
}
And the EventAdapter is
public class EventAdapter extends XmlAdapter<EventAdapter.AdaptedMap, Map<Event, String>> {
public static class AdaptedMap {
#XmlVariableNode("key")
List<AdaptedEntry> entries = new ArrayList<AdaptedEntry>();
}
public static class AdaptedEntry {
#XmlTransient
public String key;
#XmlValue
public String value;
}
.....
}
my output was
<element>
<events>
<onCellEdit>do some thing<onCellEdit>
</events>
<entityType>com.agitech.erp.model.erp.ErpFolder</entityType>
<element>
I try to remove the <events> tag by adding #XmlPath(".")
#XmlPath(".")
#XmlJavaTypeAdapter(value=EventAdapter.class)
public Map<Event, String> getEvents() {
}
The output is good
<element>
<onCellEdit>do some thing<onCellEdit>
<entityType>com.agitech.erp.model.erp.ErpFolder</entityType>
<element>
but the unmarchaling faileds
Caused by: Exception [EclipseLink-3002] (Eclipse Persistence Services - 2.6.0.v20140809-296a69f): org.eclipse.persistence.exceptions.ConversionException
Exception Description: The object [], of class [class java.lang.String], from mapping [org.eclipse.persistence.oxm.mappings.XMLDirectMapping[entityType-->view.entityType/text()]] with descriptor [XMLDescriptor(com.agitech.erp.view.BeanView --> [DatabaseTable(view), DatabaseTable(viewFrame), DatabaseTable(viewElement)])], could not be converted to [class java.lang.Class].
Internal Exception: java.lang.ClassNotFoundException:
at org.eclipse.persistence.exceptions.ConversionException.couldNotBeConvertedToClass(ConversionException.java:95)
at org.eclipse.persistence.internal.helper.ConversionManager.convertObjectToClass(ConversionManager.java:446)
Debuging Jaxb bring me to the line
org.eclipse.persistence.internal.oxm.XMLDirectMappingNodeValue
public void endElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord) {
...
line 205 unmarshalRecord.setAttributeValue(convertedValue, xmlDirectMapping);
}
During the unmarchaling of entityType value, the UnmarshalRecordImpl.currentObj contains the EventAdapter instead of the parent element
I modify org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl
public XPathNode getNonAttributeXPathNode(String namespaceURI, String localName, String qName, Attributes attributes) {
....
if(null == resultNode && null == nonPredicateNode) {
// ANY MAPPING
resultNode = xPathNode.getAnyNode();
// by default it return the EventAdapter, changing it to NULL fix my problem
}
....
}
Not a safe solution
I have been able to reproduce the issue that you are seeing, but haven't yet worked out the cause. You can use the following bug to track the progress on this issue:
http://bugs.eclipse.org/457169
After trying a lot of things, I was able to find a workaround for this issue. I thought of posting here the same so it can be helpful to someone else in the future. The lead has confirmed the issue around 5 years ago but seems like they have not fixed it and I was facing a similar issue.
Basically, we can use the beforeMarshal and afterUnmarshal methods to change the values in the fields.
You need to create a field List<Object> with #XmlAnyElement(lax=true) along with Map<String,Object>.
Remove the #XmlPath(".") and the XMLAdapter class.
Mark the field Map<String, Object> with #XmlTransient.
Now within the beforeMarshal and afterMarshal fields, you can exchange the data. During the unmarshal in beforeunmarshal, all the unknown field values will be present within the List<Object> loop over it and add it to the Map<String, Object>.
Similarly during the marshaling, you can move the values Map<String, Object> to List<Object> by creating the DOM elements.
Marshaling all values are added to root as DOM Elements are present and during Unmarshaling known values are read first and then-unknown values are stored within List<Object> due to #XmlAnyElement.
I have created an example using the Customer class, you can modify it accordingly for your need.
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "isA")
#JsonInclude(Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
#XmlRootElement(name = "Customer")
#XmlType(name = "Customer", propOrder = {"name", "age", "otherElements"})
#XmlAccessorType(XmlAccessType.FIELD)
#Getter
#Setter
#AllArgsConstructor
#ToString
#NoArgsConstructor
public class Customer {
#XmlTransient
private String isA;
private String name;
private String age;
#XmlAnyElement(lax = true)
#JsonIgnore
private List<Object> otherElements = new ArrayList<>();
#JsonIgnore
#XmlTransient
private Map<String, Object> userExtensions = new HashMap<>();
#JsonAnyGetter
#JsonSerialize(using = CustomExtensionsSerializer.class)
public Map<String, Object> getUserExtensions() {
return userExtensions;
}
#JsonAnySetter
public void setUserExtensions(String key, Object value) {
userExtensions.put(key, value);
}
private void beforeMarshal(Marshaller m) throws ParserConfigurationException {
System.out.println("Before Marshalling User Extension: " + userExtensions);
ExtensionsModifier extensionsModifier = new ExtensionsModifier();
otherElements = extensionsModifier.Marshalling(userExtensions);
System.out.println("Before Marshalling Final Other Elements " + otherElements);
userExtensions = new HashMap<>();
}
private void afterUnmarshal(Unmarshaller m, Object parent) throws ParserConfigurationException {
System.out.println("After Unmarshalling : " + otherElements);
ExtensionsModifier extensionsModifier = new ExtensionsModifier();
userExtensions = extensionsModifier.Unmarshalling(otherElements);
otherElements = new ArrayList();
}
}
You can refer the creation of DOM ELEMENTS here:https://stackoverflow.com/a/24239105/7584240
You can refer my complete answer here: https://stackoverflow.com/a/67923216/7584240

How to resolve unmarshalling exception?

I am trying to learn JAXB. I created sample as below, but during unmarshalling i am getting exception. My files are below. Can you help me to resolve?
AddRequest.java:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "AddRequest", namespace = "http://www.example.org/AddRequest", propOrder = {
"first",
"sec",
"any"
})
public class AddRequest {
#XmlElement(name = "First")
protected int first;
#XmlElement(name = "Sec")
protected int sec;
#XmlAnyElement(lax = true)
protected List<Object> any;
}
ObjectFactory.java
#XmlRegistry
public class ObjectFactory {
private final static QName _AddRequest_QNAME = new QName("http://www.example.org/AddRequest", "AddRequest");
public ObjectFactory() {
}
public AddRequest createAddRequest() {
return new AddRequest();
}
#XmlElementDecl(namespace = "http://www.example.org/AddRequest", name = "AddRequest")
public JAXBElement<AddRequest> createAddRequest(AddRequest value) {
return new JAXBElement<AddRequest>(_AddRequest_QNAME, AddRequest.class, null, value);
}
}
package-info.java
#javax.xml.bind.annotation.XmlSchema(namespace = "http://www.example.org/AddRequest", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.example.addrequest;
Main.java
try {
File file = new File("C:\\Users\\nbkyooh\\IBM\\rationalsdp\\workspace\\Sample\\resource\\AddRequest.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(org.example.addrequest.AddRequest.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
jaxbUnmarshaller.unmarshal(file);
} catch (JAXBException e) {
e.printStackTrace();
}
AddRequest.xml
<?xml version="1.0" encoding="UTF-8"?>
<tns:AddRequest xmlns:tns="http://www.example.org/AddRequest" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/AddRequest AddRequest.xsd ">
<tns:First>0</tns:First>
<tns:Sec>0</tns:Sec>
</tns:AddRequest>
I am getting exception as below, what i have done wrong. I used all the generated files.
javax.xml.bind.UnmarshalException: Unexpected element "{http://www.example.org/AddRequest}AddRequest". Expected elements are "".
at com.ibm.xml.xlxp2.jaxb.msg.JAXBMessageProvider.throwUnmarshalExceptionWrapper(JAXBMessageProvider.java:93)
at com.ibm.xml.xlxp2.jaxb.unmarshal.impl.DeserializationContext.handleSkippedRootElementEvent(DeserializationContext.java:318)
at com.ibm.xml.xlxp2.jaxb.unmarshal.impl.JAXBDocumentScanner.produceRootElementEvent(JAXBDocumentScanner.java:189)
try this:
try {
FileInputStream inputStream = new FileInputStream(new File("your file"));
AddRequest req = JAXB.unmarshal(inputStream, AddRequest.class);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
In your use case you have define the root element information leveraging the #XmlElementDecl annotation on a ObjectFactory class annotated with #XmlRegistry (see: http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html). Since the class annotated with #XmlRegistry can be called anything and JAXB doesn't do package scanning you need to include your ObjectFactory as one of the classes passed in to bootstrap the JAXBContext.
JAXBContext.newInstance(AddRequest.class, ObjectFactory.class);
Since the ObjectFactory class references AddRequest you could simplify this down to:
JAXBContext.newInstance(ObjectFactory.class);

javassist not injecting annotation at existing field

I'm trying to inject JAXB annotation at runtime using Javassist. I have written following code:
public class AssistAnnotationInjector {
public static void addAnnotationRunTime(String className, String fieldName) throws NotFoundException, CannotCompileException, IOException, ClassNotFoundException{
CtClass ctClass = ClassPool.getDefault().get(className);
ClassFile ccFile = ctClass.getClassFile();
ConstPool constPool = ccFile.getConstPool();
AnnotationsAttribute attr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
Annotation annot = new Annotation("javax.xml.bind.annotation.XmlTransient",constPool);
attr.addAnnotation(annot);
CtField field = ctClass.getDeclaredField(fieldName);
field.getFieldInfo().addAttribute(attr);
System.out.println(field.getAnnotation(XmlTransient.class));
ccFile.setVersionToJava5();
ctClass.writeFile();
}
public static void main (String args[]) throws CannotCompileException, NotFoundException, IOException, SecurityException, NoSuchMethodException, ClassNotFoundException, JAXBException, NoSuchFieldException{
Person<Student> p = new Person<Student>();
p.setName("XYZ");
Student s = new Student();
s.setName("ABC");
s.setId("239423");
p.setPayload(s);
addAnnotationRunTime("RuntimeAnnotation.Person", "name");
Field f = p.getClass().getDeclaredField("name");
System.out.println(f.getAnnotation(XmlTransient.class));
JAXBContext context = JAXBContext.newInstance(p.getClass());
Marshaller mr = context.createMarshaller();
mr.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
mr.marshal(p, System.out);
}
}
And Person.java class is:
#XmlRootElement(name="Person")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlSeeAlso({Student.class})
public class Person <T>{
private T payload;
private String name;
public void setPayload(T payload){
this.payload = payload;
}
public T getPayload(){
return payload;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
}
In AssistAnnotationInjector.java, I am trying to add XmlTransient annotation to 'name' field. But the name field is still coming in marshalling output. Why is it so?
PS: marshal output is :
#javax.xml.bind.annotation.XmlTransient
null
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Person>
<payload xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="student">
<name>ABC</name>
<id>239423</id>
</payload>
**<name>XYZ</name>**
</Person>
name tag was not expected to present in output..
You basicaly have 2 options:
do the modification before you load the class. You can not use reflection in the normal way! One can try to use org.reflections with Maven plugin to pre-fetch classes. See here for more info.
use custom classloader to load the modified class. See here for more info.
After adding the attribute to the field you need to call ctClass.toClass() method,which freezes the class. After this you can check for the annotation.

Resources