XStreamAsAttribute not adding as attribute - xstream - jaxb

I wrote a class which will be converted by xstream into xml .
I added #XStreamAsAttribute to add xmlns as an attribute . But it got added as a nested tag in the output
My class file is as follows
#XStreamAlias("GetConfigurationParametersResponse")
public class GetConfigurationParametersResponse
extends BaseResponse
{
#XStreamAlias("xmlns")
#XStreamAsAttribute
final String xmlns = "http://www.collab.net/teamforge/integratedapp";
#XStreamAlias("xmlns:ns2")
#XStreamAsAttribute
final String ns2="http://www.collab.net/teamforge/integratedapp";
#XStreamImplicit(itemFieldName="ConfigurationParameter")
protected List<ConfigurationParameter> configurationParameter;
public List<ConfigurationParameter> getConfigurationParameter() {
if (configurationParameter == null) {
configurationParameter = new ArrayList<ConfigurationParameter>();
}
return this.configurationParameter;
}
}
The output for this is as follows
<com.collabnet.teamforge.ia.GetConfigurationParametersResponse>
<xmlns>http://www.collab.net/teamforge/integratedapp</xmlns>
<ns2>http://www.collab.net/teamforge/integratedapp</ns2>
</com.collabnet.teamforge.ia.GetConfigurationParametersResponse>
But I need output as
<com.collabnet.teamforge.ia.GetConfigurationParametersResponse xmlns="http://www.collab.net/teamforge/integratedapp" xmlns:ns2="http://www.collab.net/teamforge/integratedapp">
</com.collabnet.teamforge.ia.GetConfigurationParametersResponse>
Please help in finding out where I am going wrong .
I followed this tutorial http://x-stream.github.io/annotations-tutorial.html

You probably need to do the following:
xstream.processAnnotations(GetConfigurationParametersResponse.class);
If only the following is being called:
xstream.processAnnotations(BaseResponse.class);
Then you could use the #XStreamInclude annotation on BaseResponse as follows:
#XStreamInclude({GetConfigurationParametersResponse.class})
public class BaseResponse {
}

What worked for me was:
xstream.autodetectAnnotations(true);

Related

How to apply `#POJO` to classes via config script?

I have a few classes which I'd like to keep as POJO. Manually annotating each of these would be troublesome, for both updating all current ones and adding future such classes.
I have a SourceAwareCustomizer able to identify all these classes. However I do not know how to apply the #POJO via the config script.
I tried ast(POJO), and I would get an error:
Provided class doesn't look like an AST #interface
I dug in the code a bit and found that #POJO is not an AST transformation (it's not annotated with #GroovyASTTransformationClass.
Is there a way to apply #POJO, or maybe a random annotation, to a class via the config script?
POJO is not an AST transformation.
Compare POJO source to ToString (for example). In POJO the GroovyASTTransformationClass annotation is missing..
I can't make #POJO working without #CompileStatic..
So, here is my try with groovy 4.0.1:
congig.groovy
import org.codehaus.groovy.ast.ClassNode
import org.codehaus.groovy.ast.AnnotationNode
import groovy.transform.stc.POJO
import groovy.transform.CompileStatic
withConfig(configuration) {
inline(phase:'SEMANTIC_ANALYSIS'){Object...args->
if(args.size()>2){
ClassNode cn = args[2]
if( cn.getSuperClass().name=="java.lang.Object" ) {
if( !cn.annotations.find{it.classNode.name==POJO.class.name} ) {
cn.addAnnotation( new AnnotationNode(new ClassNode(POJO.class)) )
//can't see how POJO could work without compile static in groovy 4.0.1
if( !cn.annotations.find{it.classNode.name==CompileStatic.class.name} )
cn.addAnnotation( new AnnotationNode(new ClassNode(CompileStatic.class)) )
}
}
println "class = $cn"
println "annotations = ${cn.getAnnotations()}"
}
}
}
A.groovy
class A{
String id
}
compile command line:
groovyc --configscript config.groovy A.groovy
generated class
public class A
{
private String id;
#Generated
public A() {}
#Generated
public String getId() {
return this.id;
}
#Generated
public void setId(final String id) {
this.id = id;
}
}

How to set the namespace of marshalled xml using camel jaxb?

For starters, I'm creating some routes using Camel ver 2.15 (in Fuse 6.2.1).
In my route, i'm trying to create a XML from a pojo that was generated using cxf-xjc maven plugin (cxf-xjc read some xsd somewhere then from the xsd, the pojos with jaxb annotations were produced).
The pojos are TempProject and TempProjects.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(
name = "",
propOrder = {"ecode", "tempName"}
)
#XmlRootElement(
name = "TempProject"
)
public class TempProject implements Serializable {
#XmlElement(
name = "Ecode",
required = true
)
protected String ecode;
#XmlElement(
name = "TempName",
required = true
)
protected String tempName;
public TempProject() {
}
public String getEcode() {
return this.ecode;
}
public void setEcode(String value) {
this.ecode = value;
}
public String getTempName() {
return this.tempName;
}
public void setTempName(String value) {
this.tempName = value;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(
name = "",
propOrder = {"tempProjects"}
)
#XmlRootElement(
name = "TempProjects"
)
public class TempProjects implements Serializable {
#XmlElement(
name = "TempProject",
required = true
)
protected List<TempProject> tempProjects;
public TempProjects() {
}
public List<TempProject> getTempProjects() {
if (this.tempProjects == null) {
this.tempProjects = new ArrayList();
}
return this.tempProjects;
}
}
I can generate the xml using this code:
JAXBContext jaxbContext = JAXBContext.newInstance(new Class[]{TempProjects.class});
jaxbContext.createMarshaller();
JaxbDataFormat jaxbDataFormat = new JaxbDataFormat(jaxbContext); //import org.apache.camel.converter.jaxb.JaxbDataFormat;
I call
.marshal(jaxbDataFormat)
in my route to effect the marshalling from the pojo to xml.
The generated xml is posted below:
<TempProjects xmlns="http://blah.blah/foo/schema/v2">
<TempProject>
<Ecode>1</Ecode>
<TempName>Tempname1</TempName>
</TempProject>
<TempProject>
<Ecode>2</Ecode>
<TempName>Tempname2</TempName>
</TempProject>
How can i generate a marshalled xml that will have a namespace like this...
<TempProjects xmlns:myprefix="http://blah.blah/foo/schema/v2">
Reason being why I needed a namespaceprefix is because I plan to split the values (e.g. Ecode) in the xml using xpath and I needed a namespaceprefix to do that (thats what ive researched, i might be wrong).
My planned code in my route is
.marshal(jaxbDataFormat)
.split( xpath("/TempProjects/TempProject/Ecode/text()").namespaces(ns1),
new ProjectIdsAggregator()) //the above xpath doesn't work because it doesn't have a namespace prefix
//Namespaces ns1 = new Namespaces("myprefix", "http://blah.blah/foo/schema/v2" );
I looked at jaxbDataFormat.setNamespacePrefixRef("myprefix"), but i got an error (org.apache.camel.NoSuchBeanException: No bean could be found in the registry for: myprefix of type: java.util.Map)
I'm actually quite new in the apache camel routing world, so i might be missing some basic stuff.
You don't need to change your XML at all. It is fine.
With the XML you posted and the Namespace declaration you posted, the following XPath works fine to split the XML (as an example) into two TempProject parts:
xpath("/myprefix:TempProjects/myprefix:TempProject").namespaces(ns1)
Because you declared the XML namespace like this:
Namespaces ns1 = new Namespaces("myprefix", "http://blah.blah/foo/schema/v2" )
Your XPath must use the prefix myprefix for all elements:
/myprefix:TempProjects/myprefix:TempProject

Is the #Repeatable annotation not supported by Groovy?

I'm coding in Groovy and am having trouble with the Java 8 #Repeatable meta-annotation. I think I'm doing everything right, but it appears that Groovy is not recognizing #Repeatable. Here's my sample code; I'm expecting the information from both annotations to get stored in MyAnnotationArray:
import java.lang.annotation.*
class MyClass
{
#MyAnnotation(value = "val1")
#MyAnnotation(value = "val2")
void annotatedMethod()
{
println("annotated method called")
}
public static void main(String... args)
{
MyClass ob = new MyClass()
ob.annotatedMethod()
java.lang.reflect.Method m = ob.getClass().getMethod("annotatedMethod")
List annos = m.getAnnotations()
println("annos = $annos")
}
}
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#Repeatable(MyAnnotationArray)
public #interface MyAnnotation
{
String value() default "val0";
}
public #interface MyAnnotationArray
{
MyAnnotation[] MyAnnotationArray()
}
What happens is that I get this error:
Caught: java.lang.annotation.AnnotationFormatError: Duplicate annotation for class: interface MyAnnotation: #MyAnnotation(value=val2)
java.lang.annotation.AnnotationFormatError: Duplicate annotation for class: interface MyAnnotation: #MyAnnotation(value=val2)
Which is exactly what I get if I leave out the #Repeatable meta-annotation.
The code works fine if I leave out one of the duplicate MyAnnotations; then there is no error, and I then can read the annotation value as expected.
Is it possible that Groovy doesn't support the #Repeatable meta-annotation? I couldn't find any documentation that states this outright, though this page hints that maybe this is the case (scroll down to item 88).
seems to be not supported
i used java 1.8 and groovy 2.4.11
after compiling and de-compilig the same code i got this:
java:
#MyAnnotationArray({#MyAnnotation("val1"), #MyAnnotation("val2")})
public void annotatedMethod()
{
System.out.println("annotated method called");
}
groovy:
#MyAnnotation("val1")
#MyAnnotation("val2")
public void annotatedMethod()
{
System.out.println("annotated method called");null;
}
so, as workaround in groovy use
//note the square brackets
#MyAnnotationArray( [#MyAnnotation("val1"), #MyAnnotation("val2")] )
public void annotatedMethod()
{
System.out.println("annotated method called");
}
full script (because there were some errors in annotation declaration)
import java.lang.annotation.*
class MyClass
{
//#MyAnnotation(value = "val1")
//#MyAnnotation(value = "val2")
#MyAnnotationArray( [#MyAnnotation("val1"), #MyAnnotation("val2")] )
public void annotatedMethod()
{
System.out.println("annotated method called");
}
public static void main(String... args)
{
MyClass ob = new MyClass()
ob.annotatedMethod()
java.lang.reflect.Method m = ob.getClass().getMethod("annotatedMethod")
List annos = m.getAnnotations()
println("annos = $annos")
}
}
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#Repeatable(MyAnnotationArray)
public #interface MyAnnotation
{
String value() default "val0";
}
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotationArray
{
MyAnnotation[] value()
}
also tried against groovy 3.0.0-SNAPSHOT - the result is the same as for 2.4.11
Yes, Groovy has supported "repeatable" annotations for a long time even in Java 5 so long as retention policy was only SOURCE. This is what allows multiple #Grab statements for instance without the outer #Grapes container annotation. Being only retained in SOURCE makes them useful for AST transformations and within the Groovy compiler itself (and other source processors) but not really useful anywhere else. We don't currently support #Repeatable at all but plan to in a future version.

Inheriting from Own class instead from XMLParserRuleContext

I am using the 'visitor' pattern to generate XML from my parsed code. On typical context class looks like:
public static class On_dtmContext extends ParserRuleContext {
public List<FieldContext> field() {
return getRuleContexts(FieldContext.class);
}
public TerminalNode ON() { return getToken(SRC_REP_SCREENParser.ON, 0); }
public On_dtm_headerContext on_dtm_header() {
return getRuleContext(On_dtm_headerContext.class,0);
}
.....
}
and I access the element in my visitors call back function using RuleContext's 'getText' member function.
I would like to write a class inheriting from 'ParserRuleContext' and overload 'getText' in order to replace characters like '<' or '>' with their xml escape sequences. Is there a way I can have my code generated and having the context classes inheriting from my class, as:
public static class On_dtmContext extends XMLParserRuleContext {
public List<FieldContext> field() {
return getRuleContexts(FieldContext.class);
}
public TerminalNode ON() { return getToken(SRC_REP_SCREENParser.ON, 0); }
public On_dtm_headerContext on_dtm_header() {
return getRuleContext(On_dtm_headerContext.class,0);
}
.....
}
Thank you for your help!
Kind regards, wolf
Is there a reason why you are trying to extend the class, rather than creating a parser rule in your grammar to capture < and > so you can translate them as they occur?
The parser rules would look something like:
lessThan
: '<'
;
greaterThan
: '>'
;
At that point, you would have specific visitors for each of those terms and could translate them as you will.

Output empty elements

I have a Object with two fields "name" and "address". JAXB ignores the empty elements while transforming the object into XMl.
For ex: if I have name="xyz" and address=null then out will be
<name>xyz</name>
but what I want as an output as
<name>xyz</name>
<address></address>
I have seen the option #XmlElement(nillable="true") but this gives the output as
<name>xyz</name>
<address xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
Please help me getting the desired output.
Thanks in advance.
A JAXB (JSR-222) implementation will output an empty String "" value as an empty element. You can set the address property to this to get the desired effect.
UPDATE #1
I have updated my question. Basically the address element is NULL. Is
this solution applicable to that as well?
You could leverage Marshal Event Callbacks to adjust the value of address.
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
private String name;
private String address;
private void beforeMarshal(Marshaller marshaller) {
if(null == address) {
address = "";
}
}
private void afterMarshal(Marshaller marshaller) {
if("".equals(address)) {
address = null;
}
}
}
UPDATE #2
The only concern is that if I have 10 fields in the class I will have
to write if for all the fields. Is there any other solution?
If you use EclipseLink MOXy as your JAXB provider (I'm the MOXy lead), then you could use an XmlAdapter for this use case.
XmlAdapter (StringAdapter)
package forum14691333;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class StringAdapter extends XmlAdapter<String, String> {
#Override
public String marshal(String string) throws Exception {
if(null == string) {
return "";
}
return string;
}
#Override
public String unmarshal(String string) throws Exception {
if("".equals(string)) {
return null;
}
return string;
}
}
package-info
Then if you specify it at the package level it will apply to all mapped fields/properties of type String within that package.
#XmlJavaTypeAdapter(value=StringAdapter.class, type=String.class)
package forum14691333;
import javax.xml.bind.annotation.adapters.*;
For More Information
http://blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
If you use EclipseLink MOXy as your JAXB provider then you could use
#XmlNullPolicy(emptyNodeRepresentsNull = true, nullRepresentationForXml = XmlMarshalNullRepresentation.EMPTY_NODE)
#XmlElement(name = "address", nillable = true)
private String address;
By using this way, you don't have to write adapter for all the fields
Simply set an empty string default value on the field.
#XmlElement(required="true")
private String address = "";
and you will get
<address></address>

Resources