Jersey 2 Client - how to get JAXBContext - jaxb

I can find Jersey 2 documentation on using custom JAXBContext but what I can't find is documentation on reusing its JAXBContext.
I want to be able to marshal/unmarshal entities without making an HTTP request (e.g. unmarshal some XML files on the classpath, marshal/unmarshal data for database I/O, etc.).
How can I get the JAXBContext instance that my Jersey 2 Client is already using?

I still haven't figured out how to get the JAXBContext but I have figured out how to reuse it:
client.target("file:///path/to/resource")
.register((ClientRequestFilter) requestContext ->
requestContext.abortWith(Response.ok()
.entity(new FileInputStream(Paths.get(requestContext.getUri())
.toFile()))
.build()))
.request()
.get(Planet.class);
Similar ClientRequestFilters can be used for returning strings or input streams from a database, etc. or for writing to a file-system or database.

import org.glassfish.jersey.jaxb.internal.AbstractJaxbProvider;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
public class JaxbContextStore {
private JaxbProvider jaxbProvider = new JaxbProvider();
public JAXBContext getStoredJaxbContext(Class type) throws JAXBException {
return jaxbProvider.getStoredJaxbContext(type);
}
private static class JaxbProvider extends AbstractJaxbProvider {
public JaxbProvider() {
super(null);
}
#Override
public JAXBContext getStoredJaxbContext(Class type) throws JAXBException {
return super.getStoredJaxbContext(type);
}
#Override
public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) {
throw new UnsupportedOperationException();
}
#Override
public Object readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
throw new UnsupportedOperationException();
}
#Override
public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) {
throw new UnsupportedOperationException();
}
#Override
public void writeTo(Object o, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
throw new UnsupportedOperationException();
}
}
}

Related

How to unmarshall JSON array using EclipseLink MOXy JAXB provider

This seems simple, but I must be missing something. All I am trying to do is unmarshall a JSON array. I have code that works when the JSON is a simple object, but when I make it an array (ie..surround JSON with []), it fails. Here is the sample json, domain class, unmarshalling code, and exception. Any help will be greatly appreciated.
Sample JSON:
[{"CreateIndex":24988,"ModifyIndex":132476,"LockIndex":0,"Key":"Redirector","Flags":0}
]
Domain:
package eclipselink.example.moxy.json.simple.model;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.common.base.Optional;
import com.google.common.io.BaseEncoding;
import com.orbitz.consul.model.kv.ImmutableValue;
import com.orbitz.consul.util.UnsignedLongDeserializer;
#org.immutables.value.Value.Immutable
#JsonDeserialize(as = ImmutableValue.class)
#JsonSerialize(as = ImmutableValue.class)
#JsonIgnoreProperties(ignoreUnknown = true)
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class MyValue {
#XmlAttribute
private long createIndex;
#XmlAttribute
private long modifyIndex;
#XmlAttribute
private long lockIndex;
#XmlAttribute
private String key;
#XmlElement
private long flags;
#XmlElement(nillable = true)
private Optional<String> value;
#XmlElement
private Optional<String> session;
#JsonProperty("CreateIndex")
public long getCreateIndex() {
return createIndex;
}
#JsonProperty("ModifyIndex")
public long getModifyIndex() {
return modifyIndex;
}
#JsonProperty("LockIndex")
public long getLockIndex() {
return lockIndex;
}
#JsonProperty("Key")
public String getKey() {
return key;
}
#JsonProperty("Flags")
#JsonDeserialize(using=UnsignedLongDeserializer.class)
public long getFlags() {
return flags;
}
#JsonProperty("Value")
public Optional<String> getValue() {
return value;
}
#JsonProperty("Session")
public Optional<String> getSession() {
return session;
}
#JsonIgnore
#org.immutables.value.Value.Lazy
public Optional<String> getValueAsString() {
if (getValue() != null && getValue().isPresent()) {
return Optional.of(
new String(BaseEncoding.base64().decode(getValue().get()))
);
} else {
return Optional.absent();
}
}
}
Unmarshall code:
public class Main_JSON_redirector {
private static final String INPUT_XML = "META-INF/input.xml";
private static final String INPUT_JSON_URL = "http://192.168.85.186:8500/v1/kv/Redirector";
private static final File INPUT_JSON_FILE = new File("C:/Users/dnance/EclipseLink-examples/moxy/json-simple/src/main/resources/META-INF/redirector.json");
public static void main(String[] args) throws Exception {
System.out.println();
System.out.println("Running EclipseLink MOXy Simple MAIN_JSON Example");
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
JAXBContext jc = JAXBContext.newInstance(new Class[] {MyValue.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
StreamSource source = new StreamSource(INPUT_JSON_FILE);
JAXBElement<MyValue[]> jaxbElement = unmarshaller.unmarshal(source, MyValue[].class);
MyValue[] value = jaxbElement.getValue();
System.out.println("value: " + value[0].getValueAsString());
...
Exception:
Running EclipseLink MOXy Simple MAIN_JSON Example
Exception in thread "main" javax.xml.bind.UnmarshalException
- with linked exception:
[Exception [EclipseLink-25007] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor for class [Leclipselink.example.moxy.json.simple.model.MyValue; was not found in the project. For JAXB, if the JAXBContext was bootstrapped using TypeMappingInfo[] you must call a marshal method that accepts TypeMappingInfo as an input parameter.]
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.handleXMLMarshalException(JAXBUnmarshaller.java:1072)
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:341)
at eclipselink.example.moxy.json.simple.Main_JSON_redirector.main(Main_JSON_redirector.java:58)
Caused by: Exception [EclipseLink-25007] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor for class [Leclipselink.example.moxy.json.simple.model.MyValue; was not found in the project. For JAXB, if the JAXBContext was bootstrapped using TypeMappingInfo[] you must call a marshal method that accepts TypeMappingInfo as an input parameter.
at org.eclipse.persistence.exceptions.XMLMarshalException.descriptorNotFoundInProject(XMLMarshalException.java:154)
at org.eclipse.persistence.internal.oxm.Context$ContextState.getSession(Context.java:137)
at org.eclipse.persistence.oxm.XMLContext$XMLContextState.getSession(XMLContext.java:798)
at org.eclipse.persistence.oxm.XMLContext$XMLContextState.getSession(XMLContext.java:1)
at org.eclipse.persistence.internal.oxm.Context.getSession(Context.java:458)
at org.eclipse.persistence.oxm.XMLContext.getSession(XMLContext.java:366)
at org.eclipse.persistence.oxm.XMLContext.getSession(XMLContext.java:1)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:837)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:710)
at org.eclipse.persistence.internal.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:643)
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:339)
You just need to specify type class instead of array class in unmarshal method, E.g.
Collection<MyValue> myValues = (Collection<MyValue>) unmarshaller.unmarshal(source, MyValue.class).getValue();
Since you have unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false); it just works. Without it unmarshal returns JAXBElement<Collection<JAXBElement>>.

How compile Groovy source but not from filesystem

I compile single groovy source module "in fly" using GroovyClassLoader.parseClass(src) and all is ok.
But problem is when this source module imports other classes, these are not compiled yet. Traditional compiling when I start compilation of one source but other are required and ready on source path, are compiled too.
How can I use GroovyClassLoader with target to compile all other required sources NOT FROM FILESYSYSTEM.
My sources are for example in database, remote http via URI etc.
The key is to make custom URL handling -- you have to implement a URLStreamHandler and a URLConnection.
If you google around, there's some good documentation on how to implement the stream handler and connection classes -- but for what you're doing, you really only need dummy implementations.
Here's some source code to bootstrap you -- it demonstrates how to connect the pieces up. If you provide some implementation of lookupScriptCodeWithJDBCorWhatever you'll be good to go.
import groovy.lang.GroovyResourceLoader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
public class CustomGroovyResourceLoader implements GroovyResourceLoader {
private final GroovyResourceLoader parentLoader;
public CustomGroovyResourceLoader(GroovyResourceLoader parentLoader) {
this.parentLoader = parentLoader;
}
#Override
public URL loadGroovySource(String filename) throws MalformedURLException {
URL resourceURL = null;
if (parentLoader != null) {
resourceURL = parentLoader.loadGroovySource(filename);
}
if (resourceURL == null) {
resourceURL = createURL(filename);
}
return resourceURL;
}
public URL createURL(String resourceName) throws MalformedURLException {
String scriptSourceCode = lookupScriptCodeWithJDBCorWhatever(resourceName);
return new URL(null, "groovy:///" + resourceName,
new GroovyResourceStreamHandler(scriptSourceCode));
}
private String lookupScriptCodeWithJDBCorWhatever(String resourceName) {
//TODO: blah blah blah
return null;
}
class GroovyResourceConnection extends URLConnection {
private final String urlData;
protected GroovyResourceConnection(URL url, String logic) {
super(url);
this.urlData = logic;
}
#Override
public void connect() throws IOException {}
#Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(urlData.getBytes());
}
}
class GroovyResourceStreamHandler extends URLStreamHandler {
private final String scriptSource;
public GroovyResourceStreamHandler(String scriptSource) {
this.scriptSource = scriptSource;
}
#Override
protected URLConnection openConnection(URL u) throws IOException {
GroovyResourceConnection connection = new GroovyResourceConnection(u, scriptSource);
return connection;
}
}
}
You then install this thing with some code that looks like this:
GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
groovyClassLoader.setResourceLoader( new CustomGroovyResourceLoader( groovyClassLoader.getResourceLoader() ) );

JaxB XmlSeeAlso, XmlElementRef, newInstance with Classes

The answer to my question
JaxB reference resolving
led me to further pursue the details of the issue regarding the use of XmlSeeAlso, XmlElementReference and the specification of classes involved in JaxbContext.newInstance.
I started with trying to answer the question:
Is it possible to #XmlSeeAlso on a class without no-args constructor which has #XmlJavaTypeAdapter?
i created the Junit test below. To do so I came accross:
#XmlJavaTypeAdapter w/ Inheritance
#XmlSeeAlso alternative
In this state the code is compilable and runs - it marshals o.k. but does not umarshal as expected.
The marshal result is:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Message>
<BasicInfo ref="id001"/>
</Message>
Unmarshalling does not create a BasicInfo as would be expected from the code in the Adapter:
public BasicInfo unmarshal(BasicInfoRef info) throws Exception {
BasicInfo binfo=new BasicInfo();
binfo.id=info.ref;
return binfo;
}
I find this all very confusing - things seem to be somewhat contradictory and mostly do not work as I'd expect regarding the JaxB settings involved. Most combinations do not work, those that do work do not give the full result yet. I assume that is also depending on the version and implementation being used.
What nees to be done to get this working?
What is a minimal set of XmlElementRef,XmlSeeAlso and JaxbContext newInstance referencing of the necessary classes?
How can I check which JaxB Implementation is being used? I am using EclipseLink 2.3.2? and I'm not sure whether this uses MoxY or not.
Update:
after consideration of:
JAXB xsi:type subclass unmarshalling not working
http://www.java.net/node/654579
http://jaxb.java.net/faq/#jaxb_version
http://www.eclipse.org/eclipselink/documentation/2.4/moxy/type_level003.htm
Can JAXB marshal by containment at first then marshal by #XmlIDREF for subsequent references?
The modified code below is close to what is intended.
Errors that showed up while trying were:
javax.xml.bind.MarshalException
- with linked exception:
[com.sun.istack.SAXException2: unable to marshal type "com.bitplan.storage.jaxb.TestRefId$BasicInfo$BasicInfoRef" as an element because it is missing an #XmlRootElement annotation]
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:323)
The code has quite a few comments which can be commented in and out to find out what happens if one tries ...
I still have no clue what the optimal solution would be to avoid superfluous annotations.
modified code:
package com.bitplan.storage.jaxb;
import static org.junit.Assert.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorNode;
import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorValue;
import org.junit.Test;
/**
* Test the Reference/Id handling for Jaxb
*
* #author wf
*
*/
public class TestRefId {
#XmlDiscriminatorNode("#reforid")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlJavaTypeAdapter(RefOrId.Adapter.class)
public static class RefOrId {
#XmlAttribute(name = "reforid")
public String reforid;
public RefOrId() {
}
#XmlAttribute
public String id;
#XmlAttribute
public String ref;
public static class Adapter extends XmlAdapter<RefOrId, RefOrId> {
#Override
public RefOrId marshal(RefOrId idref) throws Exception {
if (idref == null)
return null;
System.out.println("marshalling " + idref.getClass().getSimpleName()
+ " reforid:" + idref.reforid);
if (idref instanceof Ref)
return new Id(((Ref) idref).ref);
return idref;
}
#Override
public RefOrId unmarshal(RefOrId idref) throws Exception {
System.out.println("unmarshalling " + idref.getClass().getSimpleName()
+ " reforid:" + idref.reforid);
return idref;
}
}
}
#XmlDiscriminatorValue("id")
#XmlAccessorType(XmlAccessType.FIELD)
public static class Id extends RefOrId {
public Id() {
reforid = "id";
}
public Id(String pId) {
this();
this.id = pId;
}
}
#XmlDiscriminatorValue("ref")
#XmlAccessorType(XmlAccessType.FIELD)
public static class Ref extends RefOrId {
public Ref() {
reforid = "ref";
}
public Ref(String pRef) {
this();
this.ref = pRef;
}
}
/*
* https://stackoverflow.com/questions/8292427/is-it-possible-to-xmlseealso-on-a
* -class-without-no-args-constructor-which-has
*/
#XmlRootElement(name = "BasicInfo")
public static class BasicInfo {
public BasicInfo() {
};
public BasicInfo(String pId, String pInfo) {
this.id = new Id(pId);
this.basic = pInfo;
}
// #XmlTransient
public RefOrId id;
public String basic;
}
#XmlRootElement(name = "SpecificInfoA")
// #XmlJavaTypeAdapter(BasicInfo.Adapter.class)
public static class SpecificInfoA extends BasicInfo {
public SpecificInfoA() {
};
public SpecificInfoA(String pId, String pInfo, String pInfoA) {
super(pId, pInfo);
infoA = pInfoA;
}
public String infoA;
}
#XmlRootElement(name = "Message")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlSeeAlso({ SpecificInfoA.class, BasicInfo.class })
public static class Message {
public Message() {
};
public Message(BasicInfo pBasicInfo) {
basicInfos.add(pBasicInfo);
}
// #XmlJavaTypeAdapter(BasicInfo.Adapter.class)
// #XmlElement(name="basicInfo",type=BasicInfoRef.class)
#XmlElementWrapper(name = "infos")
#XmlElement(name = "info")
public List<BasicInfo> basicInfos = new ArrayList<BasicInfo>();
}
/**
* marshal the given message
*
* #param jaxbContext
* #param message
* #return - the xml string
* #throws JAXBException
*/
public String marshalMessage(JAXBContext jaxbContext, Message message)
throws JAXBException {
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter sw = new StringWriter();
jaxbMarshaller.marshal(message, sw);
String xml = sw.toString();
return xml;
}
/**
* test marshalling and umarshalling a message
*
* #param message
* #throws JAXBException
*/
public void testMessage(Message message) throws JAXBException {
#SuppressWarnings("rawtypes")
Class[] classes = { Message.class, SpecificInfoA.class, BasicInfo.class }; // BasicInfo.class,};
// https://stackoverflow.com/questions/8318231/xmlseealso-alternative/8318490#8318490
// https://stackoverflow.com/questions/11966714/xmljavatypeadapter-not-being-detected
JAXBContext jaxbContext = JAXBContext.newInstance(classes);
String xml = marshalMessage(jaxbContext, message);
System.out.println(xml);
Unmarshaller u = jaxbContext.createUnmarshaller();
Message result = (Message) u.unmarshal(new StringReader(xml));
assertNotNull(result);
assertNotNull(message.basicInfos);
for (BasicInfo binfo : message.basicInfos) {
RefOrId id = binfo.id;
assertNotNull(id);
System.out.println("basicInfo-id " + id.getClass().getSimpleName()
+ " for reforid " + id.reforid);
// assertEquals(message.basicInfo.id, result.basicInfo.id);
}
xml = marshalMessage(jaxbContext, result);
System.out.println(xml);
}
/**
* switch Moxy
*
* #param on
* #throws IOException
*/
public void switchMoxy(boolean on) throws IOException {
File moxySwitch = new File(
"src/test/java/com/bitplan/storage/jaxb/jaxb.properties");
if (on) {
PrintWriter pw = new PrintWriter(new FileWriter(moxySwitch));
pw.println("javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory");
pw.close();
} else {
moxySwitch.delete();
}
}
#Test
public void testStackOverflow8292427() throws JAXBException, IOException {
boolean[] moxyOnList = { false };
for (boolean moxyOn : moxyOnList) {
switchMoxy(moxyOn);
System.out.println("Moxy used: " + moxyOn);
Message message = new Message(new BasicInfo("basicId001",
"basicValue for basic Info"));
message.basicInfos.add(new SpecificInfoA("specificId002",
"basicValue for specific Info", "specific info"));
message.basicInfos.add(new SpecificInfoA("specificId002",
"basicValue for specific Info", "specific info"));
testMessage(message);
}
}
}
This is the Junit Test as mentioned above (before update):
package com.bitplan.storage.jaxb;
import static org.junit.Assert.*;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlElementRefs;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import org.junit.Test;
// Test the Reference/Id handling for Jaxb
public class TestRefId {
/*
* https://stackoverflow.com/questions/8292427/is-it-possible-to-xmlseealso-on-a-class-without-no-args-constructor-which-has
*/
#XmlRootElement(name="BasicInfo")
#XmlJavaTypeAdapter(BasicInfo.Adapter.class)
public static class BasicInfo {
#XmlRootElement(name="BasicInfo")
#XmlAccessorType(XmlAccessType.FIELD)
public static class BasicInfoRef {
#XmlAttribute(name = "ref")
public String ref;
}
public static class Adapter extends XmlAdapter<BasicInfoRef,BasicInfo>{
#Override
public BasicInfoRef marshal(BasicInfo info) throws Exception {
BasicInfoRef infoRef = new BasicInfoRef();
infoRef.ref=info.id;
return infoRef;
}
#Override
public BasicInfo unmarshal(BasicInfoRef info) throws Exception {
BasicInfo binfo=new BasicInfo();
binfo.id=info.ref;
return binfo;
}
} // Adapter
public String id;
public String basic;
}
#XmlJavaTypeAdapter(BasicInfo.Adapter.class)
public static class SpecificInfoA extends BasicInfo {
public String infoA;
}
#XmlRootElement(name="Message")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlSeeAlso({SpecificInfoA.class,BasicInfo.class})
public static class Message {
// https://stackoverflow.com/questions/3107548/xmljavatypeadapter-w-inheritance
#XmlElementRefs({
#XmlElementRef(name="basic", type=BasicInfo.class),
// #XmlElementRef(name="infoA", type=SpecificInfoA.class)
})
public BasicInfo basicInfo;
}
#Test
public void testStackOverflow8292427() throws JAXBException {
Message message=new Message();
SpecificInfoA info=new SpecificInfoA();
info.id="id001";
info.basic="basicValue";
info.infoA="infoAValue";
message.basicInfo=info;
#SuppressWarnings("rawtypes")
Class[] classes= {Message.class,SpecificInfoA.class,BasicInfo.class,BasicInfo.BasicInfoRef.class}; // BasicInfo.class,};
// https://stackoverflow.com/questions/8318231/xmlseealso-alternative/8318490#8318490
JAXBContext jaxbContext = JAXBContext.newInstance(classes);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter sw = new StringWriter();
jaxbMarshaller.marshal(message, sw);
String xml=sw.toString();
System.out.println(xml);
Unmarshaller u = jaxbContext.createUnmarshaller();
Message result = (Message) u.unmarshal(new StringReader(xml));
assertNotNull(result);
assertNotNull("basicInfo should not be null",result.basicInfo);
assertEquals("id001",result.basicInfo.id);
}
}

How to transfer an array list of objects over the wire through GWTP action

I am trying to create an action in which the server needs to response an array list of objects over the wire to the client through GWTP Action.
Category class
package com.business.share;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
public class Category implements Serializable{
Long id;
protected String name;
protected String description;
protected boolean status;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean getStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
}
GetCategories class
package com.business.client.action;
import java.util.ArrayList;
import com.gwtplatform.dispatch.shared.ActionImpl;
import com.business.client.action.GetCategoriesResult;
import com.business.share.Category;
public class GetCategories extends ActionImpl<GetCategoriesResult> {
private ArrayList<Category> categories;
#SuppressWarnings("unused")
public GetCategories() {
// For serialization only
}
public GetCategories(ArrayList<Category> categories) {
this.categories = categories;
}
public ArrayList<Category> getCategories() {
return categories;
}
}
GetCategoriesResult class
package com.business.client.action;
import java.util.ArrayList;
import com.gwtplatform.dispatch.shared.Result;
import com.business.share.Category;
public class GetCategoriesResult implements Result {
private ArrayList<Category> categories;
#SuppressWarnings("unused")
private GetCategoriesResult() {
// For serialization only
}
public GetCategoriesResult(ArrayList<Category> categories) {
this.categories = categories;
}
public ArrayList<Category> getCategories() {
return categories;
}
}
GetCategoriesActionHandler class
package com.business.server.handler;
import java.util.ArrayList;
import com.gwtplatform.dispatch.server.actionhandler.ActionHandler;
import com.business.client.action.GetCategories;
import com.business.client.action.GetCategoriesResult;
import com.business.share.Category;
import com.google.inject.Inject;
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.Query;
import com.gwtplatform.dispatch.server.ExecutionContext;
import com.gwtplatform.dispatch.shared.ActionException;
public class GetCategoriesActionHandler implements
ActionHandler<GetCategories, GetCategoriesResult> {
#Inject
public GetCategoriesActionHandler() {
}
#Override
public GetCategoriesResult execute(GetCategories action,
ExecutionContext context) throws ActionException {
ArrayList<Category> categories = new ArrayList<Category>();
// dummy data
Category cat1 = new Category();
cat1.setName("cat1");
cat1.setDescription("cat1 desc");
cat1.setStatus(true);
Category cat2 = new Category();
cat1.setName("cat2");
cat1.setDescription("cat2 desc");
cat1.setStatus(false);
categories.add(cat1);
categories.add(cat2);
return new GetCategoriesResult(categories);
}
#Override
public void undo(GetCategories action, GetCategoriesResult result,
ExecutionContext context) throws ActionException {
}
#Override
public Class<GetCategories> getActionType() {
return GetCategories.class;
}
}
And this is a piece of code in CategoryPresenter, which sends async to server.
#Override
protected void onReset() {
super.onReset();
GetCategories getCategoriesAction = new GetCategories();
dispatchAsync.execute(getCategoriesAction, getCategoriesCallback);
}
private final AsyncCallback<GetCategoriesResult> getCategoriesCallback =
new AsyncCallback<GetCategoriesResult>() {
#Override
public void onFailure(Throwable caught) {
}
#Override
public void onSuccess(GetCategoriesResult result) {
getView().getCategoryListBox().clear();
ArrayList<Category> categories = result.getCategories();
for(Category category : categories) {
getView().getCategoryListBox().addItem(category.getName());
}
}
};
I don't know what wrong with this piece of code, but GWT compiler always gives error like this.
Compiling module com.business.Business
Validating newly compiled units
Ignored 3 units with compilation errors in first pass.
Compile with -strict or with -logLevel set to TRACE or DEBUG to see all errors.
Finding entry point classes
[ERROR] Errors in 'file:/.blah..blah..blah../businessapp/src/com/business/client/presenter/CategoryPresenter.java'
[ERROR] Line 75: No source code is available for type com.business.share.Category; did you forget to inherit a required module?
[ERROR] Errors in 'file:/.blah..blah..blah../businessapp/src/com/business/client/action/GetCategoriesResult.java'
[ERROR] Line 11: No source code is available for type com.business.share.Category; did you forget to inherit a required module?
[ERROR] Unable to find type 'com.business.client.Business'
[ERROR] Hint: Previous compiler errors may have made this type unavailable
[ERROR] Hint: Check the inheritance chain from your module; it may not be inheriting a required module or a module may not be adding its source path entries properly
Following this error message, it means, com.business.share.Category is not found, but this file is physically stored in that package already. I don't understand why GWT could not find it. I noticed anywhere that I make call Category class, it brings this error always.
Somebody's got an idea on what's going on?
[EDIT]
The problem is solved.
In my Business.gwt.xml, I have
<source path='shared'/>
But my share package is com.business.share (without d)
I just rename the package name from share to shared.
Try to add an empty constructor to the Category class.

How to prevent marshalling empty tags in JAXB when string is empty but not null

I am trying to make JAXB do not marshal empty tags when string is empty.
I can make it by creating XmlAdapter where insted empty string null would be returned. But in that way, I will have to annotate each attribute with this adapter.
Is there any way to make it more global?
EclipseLink JAXB (MOXy) will let you specify the XmlAdapter for java.lang.String at the package level (I'm the MOXy tech lead):
package-info
#XmlJavaTypeAdapter(value=StringAdapter.class, type=String.class)
package example;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
StringAdapter
package example;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class StringAdapter extends XmlAdapter<String, String> {
#Override
public String unmarshal(String v) throws Exception {
return v;
}
#Override
public String marshal(String v) throws Exception {
if("".equals(v)) {
return null;
}
return v;
}
}
Root
package example;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Root {
private String foo;
private String bar;
public String getFoo() {
return foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
public String getBar() {
return bar;
}
public void setBar(String bar) {
this.bar = bar;
}
}
jaxb.properties
To use MOXy as your JAXB provider you need to include a file named jaxb.properties in the same package as your model classes with the following entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
package example;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
System.out.println(jc);
Root root = new Root();
root.setFoo("");
root.setBar("");
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
Note
Due to what I feel is a bug in the JAXB reference implementation, the following exception is thrown if you use the version of JAXB included in Java SE 6:
Exception in thread "main" java.lang.NullPointerException
at com.sun.xml.bind.v2.runtime.output.Encoded.setEscape(Encoded.java:107)
at com.sun.xml.bind.v2.runtime.output.UTF8XmlOutput.doText(UTF8XmlOutput.java:315)
at com.sun.xml.bind.v2.runtime.output.UTF8XmlOutput.text(UTF8XmlOutput.java:299)
at com.sun.xml.bind.v2.runtime.output.IndentingUTF8XmlOutput.text(IndentingUTF8XmlOutput.java:153)
at com.sun.xml.bind.v2.runtime.XMLSerializer.leafElement(XMLSerializer.java:325)
at com.sun.xml.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$1.writeLeafElement(RuntimeBuiltinLeafInfoImpl.java:210)
at com.sun.xml.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$1.writeLeafElement(RuntimeBuiltinLeafInfoImpl.java:209)
at com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor$CompositeTransducedAccessorImpl.writeLeafElement(TransducedAccessor.java:250)
at com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty.serializeBody(SingleElementLeafProperty.java:98)
at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:340)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:593)
at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:324)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:494)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:315)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:244)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:75)
at example.Demo.main(Demo.java:18)

Resources