Some of us still use jaxb2 maven plugins to generate JAXB (javax.xml.bind.*) annotated java using jaxb bindings and that sort of stuff. Simplexml does not have a mavenized generator. I was hoping I could somehow easily convert from jaxb to simplexml (bindings) but that ultimately means hand-changing the generated code to switch the annotations. I made this _quick'n'dirty_ implementation that can convert JAXB xml annotated pojos and be used as a replacement convertor.
Maybe someone finds this useful or we can add this to the convertor plugins?
Usage:
java
.....
.addConverterFactory(JAXBConverterFactory.create())
....
JAXBConverterFactory
````java
package retrofit2.converter.xml;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
public final class JAXBConverterFactory extends Converter.Factory {
public static JAXBConverterFactory create() {
return new JAXBConverterFactory();
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
try {
return new JAXBResponseBodyConverter<>(type);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return new JAXBRequestBodyConverter<>();
}
}
**JAXBRequestBodyConverter**
java
package retrofit2.converter.xml;
import java.io.IOException;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import retrofit2.Converter;
final class JAXBRequestBodyConverter
private static final MediaType MEDIA_TYPE = MediaType.parse("application/xml; charset=UTF-8");
@Override
public RequestBody convert(T value) throws IOException {
StringWriter writer = new StringWriter();
try {
JAXBContext context = JAXBContext.newInstance(value.getClass());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(value, writer);
} catch (JAXBException e) {
e.printStackTrace();
}
return RequestBody.create(MEDIA_TYPE, writer.toString());
}
}
**JAXBResponseBodyConverter**
java
package retrofit2.converter.xml;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Type;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import okhttp3.ResponseBody;
import retrofit2.Converter;
final class JAXBResponseBodyConverter
private final Class> clazz;
public JAXBResponseBodyConverter(Type type) throws ClassNotFoundException {
this.clazz = Class.forName(type.getTypeName());
}
@SuppressWarnings("unchecked")
@Override
public T convert(ResponseBody value) throws IOException {
try {
JAXBContext context = JAXBContext.newInstance(clazz);
Unmarshaller um = context.createUnmarshaller();
return (T) um.unmarshal(new StringReader(value.string()));
} catch (JAXBException je) {
throw new RuntimeException("Error interpreting XML response", je);
}
}
}
````
We've been hesitant to add any new first-party converters in the past, but I wouldn't mind replacing Simple XML with something more sane. I don't want to force people to use code generation though. Is there a reflection-based version of JAXB that we can maybe share code with?
Though it has its wrinkles JAXB is the best XML binder I鈥檝e used.
I understand the hesitation and I am not a fan of XML to be honest. I do love the clean SimpleXMLFramework, easy and 'simple'.
Still at this time JAXB is very actively used in the Java world. Webservice consumer generators mostly use JAXB (ex Apache CXF). In my testcase consuming 3 simple different webservices result in around 5000 lines of java code that I don't want to hand-write or convert to simplexml. The main advantage of using jaxb2 plugins when generating code is the possibility to add XMLTransient fields, ORM mappings, annotations (persist) and even code injection to allow a many other uses to applications without touching the xsd or wsdl. Adding extra functionality to generated code is as easy as changing stuff in the xjb bindings.
In my honest opinion allowing people to use generated code should be possible since it is still a basis for consuming larger interfaces.
Looks like this can be used reflectively as well so we'll probably add something and deprecate the Simple XML one for removal in the next major version. If people want to use Simple XML then someone can maintain a standalone converter for it.
it would be amazing that jaxb Converter feature will be added. I prefer to use json 1000 times, but sometimes you must interact with web services with wsdl and it is necessary to have a plugin that allows generating classes to make it easier to consume. Thanks @JakeWharton
The JaxbConverterFactory we created independently at Square.
https://gist.github.com/swankjesse/c5c9b3fd742d5083fb62bc41489a8feb
This has been merged and will be in the next release (2.4).
Most helpful comment
I understand the hesitation and I am not a fan of XML to be honest. I do love the clean SimpleXMLFramework, easy and 'simple'.
Still at this time JAXB is very actively used in the Java world. Webservice consumer generators mostly use JAXB (ex Apache CXF). In my testcase consuming 3 simple different webservices result in around 5000 lines of java code that I don't want to hand-write or convert to simplexml. The main advantage of using jaxb2 plugins when generating code is the possibility to add XMLTransient fields, ORM mappings, annotations (persist) and even code injection to allow a many other uses to applications without touching the xsd or wsdl. Adding extra functionality to generated code is as easy as changing stuff in the xjb bindings.
In my honest opinion allowing people to use generated code should be possible since it is still a basis for consuming larger interfaces.