{#========================================== Spincast Jackson XML plugin ==========================================#} {% extends "../../layout.html" %} {% block sectionClasses %}plugins plugins-spincast-jackson-xml{% endblock %} {% block meta_title %}Plugins - Spincast Jackson XML{% endblock %} {% block meta_description %}Spincast Jackson XML plugin provides XML functionalities using Jackson.{% endblock %} {% block scripts %} {% endblock %} {% block body %}
The Spincast Jackson XML plugin provides XML functionalities
using Jackson. It contains an implementation
of the IXmlManager interface.
Most of the time, the IXmlManager interface is used directly from
the request context via the
xml() method or indirectly via
some methods on the response() add-on.
For example:
{% verbatim %}
public class AppController {
public void myHandler(IDefaultRequestContext context) {
// Create a Json object from a XML String, using the "xml()" add-on
IJsonObject jsonObj = context.xml().fromXml("<user></user>");
// Send an object as XML, using the "response()" add-on
context.response().sendXmlObj(jsonObj);
}
}{% endverbatim %}
You can also directly inject the IXmlManager
instance where you need it in your application.
If you use the spincast-default artifact, this plugin is already installed so
you have nothing more to do!
If you start from scratch using the spincast-core artifact, you can use the
plugin by adding this artifact to your project:
<dependency>
<groupId>org.spincast</groupId>
<artifactId>spincast-plugins-jackson-xml</artifactId>
<version>{{spincastCurrrentVersion}}</version>
</dependency>
You then install the plugin's Guice module, by passing it to the Guice.createInjector(...) method:
Injector guice = Guice.createInjector(
new SpincastCoreGuiceModule(args),
new SpincastJacksonXmlPluginGuiceModule(IAppRequestContext.class)
// other modules...
);
... or by using the install(...) method from your custom Guice module:
public class AppModule extends SpincastCoreGuiceModule {
@Override
protected void configure() {
super.configure();
install(new SpincastJacksonXmlPluginGuiceModule(getRequestContextType()));
// other modules...
}
// ...
}
IXmlManager interface
String toXml(Object obj)
IJsonObject, its elements
of type "IJsonArray" will have a "isArray='true'" attribute
added. This way, the XML can be deserialized back to a
IJsonObject correctly.
String toXml(Object obj, boolean pretty)
IJsonObject fromXml(String xml)
IJsonObject. This
will correctly manage the XML generated by
toXml(), arrays included.
IJsonArray fromXmlToJsonArray(String xml)
IJsonArray. This
will correctly manage the XML generated by
toXml(), arrays included.
<T> T fromXml(String xml, Class<T> clazz)
IJsonObject to get the
arrays to work out of the box!
<T> T fromXmlToType(String xml, Type type)
IJsonObject to get the
arrays to work out of the box!
<T> T fromXmlInputStream(InputStream inputStream, Class<T> clazz)
IJsonObject to get the
arrays to work out of the box!
You can bind a ISpincastXmlManagerConfig implementation to tweak
the default configurations
used by the components this plugin provides. By default, the
SpincastXmlManagerConfigDefault class is used as the implementation.
int getPrettyPrinterIndentationSpaceNumber()
XML when
pretty print is used.
4 spaces.
String getPrettyPrinterNewlineChars()
XML when
pretty print is used.
\n, wathever the platform the application is running on.
Jackson allows some configuration when serializing and deserializing an object.
Most of those configurations
are defined using annotations.
You can annotate the objects directly, or you can use mix-ins.
If you don't minds annotating your objects with Jackson specific annotations,
this is maybe the simplest thing to do. For example, let's say you have a User
class that has two fields, name and title, and you don't want
to keep the title field when you
serialize an instance of this class:
public class User implements IUser {
private String name;
private String title;
@Override
public String getName() {
return this.name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getTitle() {
return this.title;
}
@Override
public void setTitle(String title) {
this.title = title;
}
}
To ignore the title field to be included during the serialization, you can simply
annotate the getTitle() method with
@JsonIgnore (yes, you use the same annotations than the ones for Json mix-ins):
public class User implements IUser {
private String name;
private String title;
@Override
public String getName() {
return this.name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
@JsonIgnore
public String getTitle() {
return this.title;
}
@Override
public void setTitle(String title) {
this.title = title;
}
}
If you serialize an instance of this class using the XML Manager,
only the name property would be kept:
IUser user = new User();
user.setName("Stromgol");
user.setTitle("alien");
String xml = getXmlManager().toXml(user);
assertNotNull(xml);
assertEquals("<User><name>Stromgol</name></User>", xml);
Many developers (us included) don't like to pollute their model classes
with too many annotations. Lucky us, Jackson provides a way to configure
objects from the outside, without annotating the objects directly, by using what is called
mix-ins annotations.
Let's start with the same User class, without any Jackson annotations:
public class User implements IUser {
private String name;
private String title;
@Override
public String getName() {
return this.name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getTitle() {
return this.title;
}
@Override
public void setTitle(String title) {
this.title = title;
}
}
To use XML mix-ins in a Spincast application, you first need to create the mix-in abstract class. Interfaces work too, but only to annotate methods, not fields.
An example mix-in for our IUser objects:
public abstract class IUserMixin implements IUser {
// Ignore this property!
@Override
@JsonIgnore
public abstract String getTitle();
}
As you can see, a mix-in extends the class/interface to configure, and adds the Jackson annotations on the overriding fields or methods declarations.
Once the mix-in is defined, you have to register it, in your custom Guice module:
public class AppModule extends SpincastDefaultGuiceModule {
public AppModule(String[] mainArgs) {
super(mainArgs);
}
@Override
protected void configure() {
super.configure();
bindXmlMixins();
//...
}
protected void bindXmlMixins() {
Multibinder<IXmlMixinInfo> xmlMixinsBinder = Multibinder.newSetBinder(binder(), IXmlMixinInfo.class);
xmlMixinsBinder.addBinding().toInstance(new XmlMixinInfo(IUser.class, IUserMixin.class));
}
}
Explanation :
XmlMixinInfo instance, which specifies the class to configure, and the
class of the mix-in used to configure it.
With this in place, Spincast will automatically configure Jackson so it uses your mix-ins, and
you would have the exact same result than annotating the User
class directly:
IUser user = new User();
user.setName("Stromgol");
user.setTitle("alien");
String xml = getXmlManager().toXml(user);
assertNotNull(xml);
assertEquals("<User><name>Stromgol</name></User>", xml);