How do I tell Xstream to serialize only fields which are annotated explicitly and ignore the rest?
I am trying to serialize a hibernate persistent object and all proxy related fields get serialized which I don’t want in my xml.
e.g.
<createdBy class="com..domain.Users " reference="../../values/createdBy"/>
is not something I want in my xml.
Edit: I don’t think I made this question clear. A class may inherit from a base class on which I have no control (as in hibernate’s case) on the base class properties.
public class A {
private String ShouldNotBeSerialized;
}
public class B extends A {
#XStreamAlias("1")
private String ThisShouldbeSerialized;
}
In this case when I serialize class B, the base class field ShouldNotBeSerialized will also get serialized. This is not something I want. In most circumstances I will not have control on class A.
Therefore I want to omit all fields by default and serialize only fields for which I explicitly specify the annotation. I want to avoid what GaryF is doing, where I need to explicitly specify the fields I need to omit.
You can omit fields with the #XstreamOmitField annotation. Straight from the manual:
#XStreamAlias("message")
class RendezvousMessage {
#XStreamOmitField
private int messageType;
#XStreamImplicit(itemFieldName="part")
private List<String> content;
#XStreamConverter(SingleValueCalendarConverter.class)
private Calendar created = new GregorianCalendar();
public RendezvousMessage(int messageType, String... content) {
this.messageType = messageType;
this.content = Arrays.asList(content);
}
}
I can take no credit for this answer, just sharing what I have found. You can override the wrapMapper method of the XStream class to achieve what you need.
This link explains in detail: http://pvoss.wordpress.com/2009/01/08/xstream/
Here is the code you need if you don't want the explanation:
// Setup XStream object so that it ignores any undefined tags
XStream xstream = new XStream() {
#Override
protected MapperWrapper wrapMapper(MapperWrapper next) {
return new MapperWrapper(next) {
#Override
public boolean shouldSerializeMember(Class definedIn,
String fieldName) {
if (definedIn == Object.class) {
return false;
}
return super
.shouldSerializeMember(definedIn, fieldName);
}
};
}
};
You might want to do all your testing before you implement this code because the exceptions thrown by the default XStream object are useful for finding spelling mistakes.
There was already a ticket for the XStream people:
Again, this is by design. XStream is a serialization tool, not a data
binding tool. It is made to serialize Java objects to XML and back. It
will write anything into XML that is necessary to recreate an equal
object graph. The generated XML can be tweaked to some extend by
configuration for convenience, but this is already an add-on. What you
like to do can be done by implementing a custom mapper, but that's a
question for the user's list and cannot be handled here.
http://jira.codehaus.org/browse/XSTR-569
I guess the only direct way is to dive into writing a MapperWrapper and exclude all fields you have not annotated. Sounds like a feature request for XStream.
Related
During deserialization, how can I pass in an extra object that's needed to initialize some class member? If I were doing deserialization "manually," the implementation might look like:
public class MyClass {
private MyDocumentObject do;
private String food;
public MyClass(JsonNode node, MyDocument document) {
this.do = document.createMyDocumentObject();
this.food = node.get("food").asText();
}
public String getFood() {
return this.food;
}
}
But I'd like to use Jackson's automatic mapping facilities and use a decorated constructor or custom deserializer, etc. and avoid implementing the deserialization within the class itself. Looking at example implementations using #JsonCreator or extending StdDeserializer, I can't see a way of saying "hey, please use this MyDocument object when you call the constructor." I'd like to avoid implementing and exposing a separate method that accepts a MyDocument that I have to invoke on every object that gets deserialized, e.g.
public createDocumentObject(MyDocument document) {
this.do = document.createMyDocumentObject();
}
I don't want to have this method at all, but if I had to, I'd want Jackson to call this method for me right after deserialization. That means I'd still have to somehow tell Jackson which MyDocument to use.
I know Gson doesn't come with a similar feature, but is there a way to add support for unwrapping Json fields the way #JsonUnwrap does?
The goal is to allow a structure like:
public class Person {
public int age;
public Name name;
}
public class Name {
public String first;
public String last;
}
to be (de)serialized as:
{
"age" : 18,
"first" : "Joey",
"last" : "Sixpack"
}
instead of:
{
"age" : 18,
"name" : {
"first" : "Joey",
"last" : "Sixpack"
}
}
I understand it could get fairly complex, so I'm not looking for a full solution, just some high-level guidelines if this is even doable.
I've made a crude implementation of a deserializer that supports this. It is fully generic (type-independent), but also expensive and fragile and I will not be using it for anything serious. I am posting only to show to others what I've got, if they end up needing to do something similar.
public class UnwrappingDeserializer implements JsonDeserializer<Object> {
//This Gson needs to be identical to the global one, sans this deserializer to prevent infinite recursion
private Gson delegate;
public UnwrappingDeserializer(Gson delegate) {
this.delegate = delegate;
}
#Override
public Object deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
Object def = delegate.fromJson(json, type); //Gson doesn't care about unknown fields
Class raw = GenericTypeReflector.erase(type);
Set<Field> unwrappedFields = ClassUtils.getAnnotatedFields(raw, GsonUnwrap.class);
for (Field field : unwrappedFields) {
AnnotatedType fieldType = GenericTypeReflector.getExactFieldType(field, type);
field.setAccessible(true);
try {
Object fieldValue = deserialize(json, fieldType.getType(), context);
field.set(def, fieldValue);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
return def;
}
}
It can then be registered globally via new GsonBuilder().registerTypeHierarchyAdapter(Object.class, new UnwrappingDeserializer(new Gson())).create() or for a specific type via registerTypeAdapter.
Notes:
A real implementation should recursively check the entire class structure for the presence of GsonUnwrap, cache the result in a concurrent map, and only go through this procedure if it needs to. Otherwise it should just return def immediately
It should also cache discovered annotated fields to avoid scanning the hierarchy each time
GenericTypeReflector is coming from GeAnTyRef
ClassUtils#getAnnotatedFields is my own implementation, but it doesn't do anything special - it just gathers declared fields (via Class#getDeclaredFields) recursively for the class hierarchy
GsonUnwrap is just a simple custom annotation
I presume a similar thing can be done for serialization as well. Examples linked from Derlin's answer can be a starting point.
Currently, there is no easy way to do that. Here are anyway some pointers/alternative ways to make it work.
GsonFire: GsonFire implements some useful features missing from Gson. While it does not yet offer automatic wrapping/unwrapping, it may be a good starting point to create your custom logic.
If you only need serialization, you can add getters for first and last in Person and use #ExposeMethodResult to serialize them. Unfortunately, setters are not supported (cf. Is possible to use setters when Gson deserializes a JSON?).
Another way to support the serialization is to follow the advices from How to move fields to parent object.
Custom TypeAdapters : on of the only ways to support both serialization and deserialization is to create custom TypeAdapters. This won't be generic, but it will suit your usecase.
The thread Serialize Nested Object as Attributes already gives you examples, so I won't repeat them here.
I have a structure of objects representing a Questionnaire and I need to serialize to JSON.
One class of the structure is a OpenQuestion and this class use generics with two parameters.
The problem starts when one of types used was Date, the date is serialized wrong, like a long.
Class code:
public class OpenQuestion <valueType,validationType> extends AbstractQuestion implements Serializable {
private valueType value;
private validationType minValue;
private validationType maxValue;
...
}
I saw how to serialize a date in a hash map if the hash map always uses a Date, but in this case I use the class with String, Integer or Date.
Any idea to solve it?
Thanks
You can add a JsonTypeInfo annotation for this. There's two ways of using this:
Get it to automatically add a type annotation to your object, so it knows what to deserialize it as.
Add a custom type resolver, to handle this for you.
The first will make your JSON ugly, but requires very little extra code and doesn't force you to make custom serializers. The latter is more difficult, but will result in cleaner JSON. Overall the problem is partly that one of your types isn't modelled in JSON (Date) so you'll probably need it to be serialised as an integer or String type in your JSON file.
The former option looks a bit like this:
#JsonTypeInfo( use = Id.CLASS, include = As.WRAPPER_PROPERTY )
private valiationType minValue;
This should encode say, a String value, as something like:
{ __type = "java.lang.String", value = "Hello, World" }
No promises on that being accurate as this is mostly from memory!
It depends. If you do know expected type, you just pass generic type reference:
OpenQuestion<Value,Validation> v = objectMapper.readValue(json,
new TypeReference<OpenQuestion<Value,Validation>>() { });
as that clues Jackson in as to expected type.
If you do not know it, then the other answer shows how to use #JsonTypeInfo.
As pointed out by #MiserableVariable, Jackson serializes (most) date fields as (numeric long) timestamps by default. You can override this behavior in a number of ways.
If using your own instance of ObjectMapper, override a property to write dates as ISO-8601:
objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
If using your own instance of ObjectMapper, to have dates written in your own custom format:
objectMapper.setDateFormat(myDateFormat); // 1.8 and above
objectMapper.getSerializationConfig().setDateFormat(myDateFormat); // for earlier versions (deprecated for 1.8+)
To leave the default serialization behavior for most fields, but override it for certain fields on certain objects, use a custom serializer:
public class MyBean implements Serializable {
private Date postDate;
// ... constructors, etc
#JsonSerialize(using = MyCustomDateSerializer.class)
public Date getPostDate() {
return postDate;
}
}
public class MyCustomDateSerializer extends JsonSerializer<Date> {
#Override
public void serialize(final Date date, final JsonGeneraror generator,
final SerializerProvider provider) throws IOException,
JSONProcessingException {
generator.writeString(yourRepresentationHere);
}
}
All of this information is available in the Jackson Documentation, with the bulk of it in the section dealing with date handling.
I'm calling a rest service that returns a json object. I'm trying to deserialize the responses to my Java Beans using Jackson and data-binding.
The example Json is something like this:
{
detail1: { property1:value1, property2:value2},
detail2: { property1:value1, property2:value2},
otherObject: {prop3:value1, prop4:[val1, val2, val3]}
}
Essentially, detail1 and detail2 are of the same structure, and thus can be represented by a single class type, whereas OtherObject is of another type.
Currently, I've set up my classes as follows (this is the structure I would prefer):
class ServiceResponse {
private Map<String, Detail> detailMap;
private OtherObject otherObject;
// getters and setters
}
class Detail {
private String property1;
private String property2;
// getters and setters
}
class OtherObject {
private String prop3;
private List<String> prop4;
// getters and setters
}
Then, just do:
String response = <call service and get json response>
ObjectMapper mapper = new ObjectMapper();
mapper.readValue(response, ServiceResponse.class)
The problem is I'm getting lost reading through the documentation about how to configure the mappings and annotations correctly to get the structure that I want. I'd like detail1, detail2 to create Detail classes, and otherObject to create an OtherObject class.
However, I also want the detail classes to be stored in a map, so that they can be easily distinguished and retrieved, and also the fact that the service in in the future will return detail3, detail4, etc. (i.e., the Map in ServiceResponse would look like
"{detail1:Detail object, detail2:Detail object, ...}).
How should these classes be annotated? Or, perhaps there's a better way to structure my classes to fit this JSON model? Appreciate any help.
Simply use #JsonAnySetter on a 2-args method in ServiceResponse, like so:
#JsonAnySetter
public void anySet(String key, Detail value) {
detailMap.put(key, value);
}
Mind you that you can only have one "property" with #JsonAnySetter as it's a fallback for unknown properties. Note that the javadocs of JsonAnySetter is incorrect, as it states that it should be applied to 1-arg methods; you can always open a minor bug in Jackson ;)
Is there any way to tell an ObjectOutputStream which fields of a serializable class should be serialized without using the keyword transient and without defining an serialPersistentFields-array?
Background: I need to use annotations to define which members of a class should be serialized (or better: not be serialized). The involved classes must implement the interface Serializable, but NOT Externalizable, so I don't want to implement the serialization/deserialization algorithm for each object but rather just use annotations for it. I can not use the transient keyword, because the annotation requires some further checks to determine whether a field should be serialized or not. These checks have to be done by the ObjectOutputStream (or in my own subclass of ObjectOutputStream). I also cannot define a serialPersistentFields-array in each class, because as explained previously, at compilation time it is not defined which fields should be serialized.
So the only thing that should be notet in the affected class is the annotation at field-level (#Target(ElementType.FIELD)).
I've tried quite a lot of approaches in the last few days, but haven't found one which is working:
The ObjectOutputStream has a method writeObjectOverride(Object) which can be used to define an own implementation of the serialization-process when extending ObjectOutputStream. This only works if the ObjectOutputStream is initialized with the no-argument-constructor because otherwise writeObjectOverride is never invoked. But this approach requires me to implement the whole serialization-process by myself and I don't want to do this, as it is quite complex and already implemented by the default ObjectOutputStream. I am looking for a way to just modify the default serialization implementation.
Another approach was extending ObjectOutputStream again and overriding writeObjectOverride(Object) (after calling enableReplaceObject(true)). In this method, I tried using some kind of SerializationProxy (see What is the Serialization Proxy Pattern?) to encapsulate the serialized object in a proxy which defines a List of Fields which should be serialized. But this approach also fails as writeObjectOverride then is also called for the List of fields (List<SerializedField> fields) in the Proxy resulting in an infinite loop.
Example:
public class AnnotationAwareObjectOutputStream extends ObjectOutputStream {
public AnnotationAwareObjectOutputStream(OutputStream out)
throws IOException {
super(out);
enableReplaceObject(true);
}
#Override
protected Object replaceObject(Object obj) throws IOException {
try {
return new SerializableProxy(obj);
} catch (Exception e) {
return new IOException(e);
}
}
private class SerializableProxy implements Serializable {
private Class<?> clazz;
private List<SerializedField> fields = new LinkedList<SerializedField>();
private SerializableProxy(Object obj) throws IllegalArgumentException,
IllegalAccessException {
clazz = obj.getClass();
for (Field field : getInheritedFields(obj.getClass())) {
// add all fields which don't have an DontSerialize-Annotation
if (!field.isAnnotationPresent(DontSerialize.class))
fields.add(new SerializedField(field.getType(), field
.get(obj)));
}
}
public Object readResolve() {
// TODO: reconstruct object of type clazz and set fields using
// reflection
return null;
}
}
private class SerializedField {
private Class<?> type;
private Object value;
public SerializedField(Class<?> type, Object value) {
this.type = type;
this.value = value;
}
}
/** return all fields including superclass-fields */
public static List<Field> getInheritedFields(Class<?> type) {
List<Field> fields = new ArrayList<Field>();
for (Class<?> c = type; c != null; c = c.getSuperclass()) {
fields.addAll(Arrays.asList(c.getDeclaredFields()));
}
return fields;
}
}
// I just use the annotation DontSerialize in this example for simlicity.
// Later on I want to parametrize the annotation and do some further checks
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
public #interface DontSerialize {
}
When I found out that it is possible to modify modifiers at runtime (see Change private static final field using Java reflection) I tried to set the transient-Modifier at runtime if the corresponding annotation was set.
Unfortunately this also does not work, because the approach used in the previous link seems to work only on static fields.
When trying it with non-static fields it runs without an exception but is not persisted because is looks like Field.class.getDeclaredField(...) returns new instances of the affected fields every time it is called:
public void setTransientTest() throws SecurityException,
NoSuchFieldException, IllegalArgumentException,
IllegalAccessException {
Class<MyClass> clazz = MyClass.class;
// anyField is defined as "private String anyField"
Field field = clazz.getDeclaredField("anyField");
System.out.println("1. is "
+ (Modifier.isTransient(field.getModifiers()) ? "" : "NOT ")
+ "transient");
Field modifiersField = Field.class.getDeclaredField("modifiers");
boolean wasAccessible = modifiersField.isAccessible();
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() | Modifier.TRANSIENT);
modifiersField.setAccessible(wasAccessible);
System.out.println("2. is "
+ (Modifier.isTransient(field.getModifiers()) ? "" : "NOT ")
+ "transient");
Field field2 = clazz.getDeclaredField("anyField");
System.out.println("3. is "
+ (Modifier.isTransient(field2.getModifiers()) ? "" : "NOT ")
+ "transient");
}
The output is:
1. is NOT transient
2. is transient
3. is NOT transient
So after calling getDeclaredField again (Field field2 = clazz.getDeclaredField("anyField");) it already lost the transient modifier.
Next approach:
Extend ObjectOutputStream and override ObjectOutputStream.PutField putFields() and define an own PutField-implementation. PutField lets you specify which (additional) fields are serialized but unfortunately the interface only has a lot of methodes of the form put(String name, <type> val) and when implementing these I cannot associate the method calls with the class field it is invoked from. For instance when serializing a field declared as private String test = "foo" the method put("test", "foo") is invoked, but I cannot associate the value of name (which is test) with the class containing the field test because no reference to the containing class is available and therefore it is impossible to read the annotation noted for the field test.
I also tried a few other approaches but as already mentioned I was not able to successfully serialize all fields except the ones with the annotation DontSerialize present.
One thing I also came across were ByteCode manipulators. Maybe it is possible with these but I have a requirement for not using any external tools - it needs to be pure Java (1.5 or 1.6).
Sorry for this really long post but I just wanted to show what I already tried and am hoping that someone can help me.
Thanks in advance.
I would reconsider if "Serialization" is really the thing you want to do. Given that the Serialization rules depends on some logic defined at runtime, the Deserialization process will be a nightmare to write.
Interesting problem, though.
Without rewriting much of Java Serialization, you will need to rewrite the bytecode. At runtime this can be done with Java Agents, but can also be done to class files during the build.