How to serialize non primitive data using JAXB? - java

I want to serialize an object using JAXB. My class definitions looks like this:
#XmlRootElement
public class MyClass{
<<How do I annotate this one?>>
private xyz_type xyz;
#XmlElement(name = "unique")
private int unique;
}
public class xyz_type extends abc_type{
private qwe_tpe qwe;
public static final ert_type ARRAY = ert_type.ARRAY;
}
Thanks for your help in advance!

You need a customer XML adapter for marshalling complex data types.
See this guide: https://www.baeldung.com/jaxb - 6. Complex Data Types

Related

Spring Boot Rest API Enumerate some Java types

I am building Spring Boot webflux REST API functionality that needs to work with data containing few Java type's (let's consider String, Integer, Double for example) information as part of JSON request/responses. Attribute representing Java type must be persistable inside mongodb as well (should not be problem once JSON can work with such attribute). I have following model class and type enumeration which is used by REST API to serialize/deserialize JSON message's.
#Getter
#ToString
#EqualsAndHashCode(exclude = "id")
#Document(collection = "core_scheme")
#JsonDeserialize(builder = SchemeModel.Builder.class)
#Builder(builderClassName = "Builder", toBuilder = true, setterPrefix = "with")
public class SchemeModel {
#Id
private final String id;
#Field(name = "userId") private final String userId;
#Field(name = "date") private final String creationDate;
#Field(name = "properties") private final Map<String, SchemeTypes> properties;
}
public enum SchemeTypes {
INTEGER, STRING, DOUBLE
}
Serialization and deserialization work's well. Now the problem is that when i want to resolve real Java type's stored inside Map<String, SchemeTypes> properties map i need to do mapping similar to this (just abstraction not real code):
SchemeTypes.INTEGER => Java Integer class
SchemeTypes.STRING => Java String class
SchemeTypes.DOUBLE => Java Double class
Is there any more simple way to represent Java type's stored inside model class and used within serialized/deserialized JSON file's so i can directly use it to deduce Java type without additional validation that it's valid Java type. For example if type's enumarated inside mentioned enum would have exactly same naming as real Java type's i could do following without any mapping:
public void deduceClass(SchemeTypes type) {
Class myClass = Class.forName(type.toString());
}
Note that i am looking for a solution which would work out of the box (i don't have to validate type's provided by user). If such solution would be harder to implement as mentioned mapping i will stick with mapping.
If you weren't saving this entity I could say you can actually directly map the SchemeTypes into corresponding class like following
public enum SchemeTypes {
INTEGER(Integer.class), STRING(String.class), DOUBLE(Double.class);
private final Class clazz;
private SchemeTypes(Class clazz){
this.clazz = clazz;
}
public Class getClazz(){
return clazz;
}
}
But as you are saving this it could cause some issue to deserialize.
Maybe you can save not the SchemaType instance directly but just the name of enum to overcome this like following
private final Map<String, String> properties;
and find the corresponding clazz value with a static method on this class like following
public static Class findClazzFor(String schemeTypeName){
return SchemeTypes.valueOf(schemeTypeName).getClazz();
}
Nevertheless I think cleanest solution would be keeping the SchemeType class instance mapping somewhere as a one-to-one map. And retrieve the corresponding class for provided schemeType as in the getClazz method above.

Jackson serialization: how to ignore superclass properties

I want to serialize a POJO class which is not under my control, but want to avoid serializing any of the properties which are coming from the superclass, and not from the final class. Example:
public class MyGeneratedRecord extends org.jooq.impl.UpdatableRecordImpl<...>,
example.generated.tables.interfaces.IMyGenerated {
public void setField1(...);
public Integer getField1();
public void setField2(...);
public Integer getField2();
...
}
You can guess from the example that that this class is generated by JOOQ, and inherits from a complex base class UpdatableRecordImpl which also has some bean property-like methods, which cause problems during the serialization. Also, I have several similar classes, so it would be good to avoid duplicating the same solution for all of my generated POJOs.
I have found the following possible solutions so far:
ignore the specific fields coming from superclass using mixin technique like this: How can I tell jackson to ignore a property for which I don't have control over the source code?
The problem with this is that if the base class changes (e.g., a new getAnything() method appears in it), it can break my implementation.
implement a custom serializer and handle the issue there. This seems a bit overkill to me.
as incidentally I have an interface which describes exactly the properties I want to serialize, maybe I can mixin a #JsonSerialize(as=IMyGenerated.class) annotation...? Can I use this for my purpose?
But, from pure design point of view, the best would be to be able to tell jackson that I want to serialize only the final class' properties, and ignore all the inherited ones. Is there a way to do that?
Thanks in advance.
You can register a custom Jackson annotation intropector which would ignore all the properties that come from the certain super type. Here is an example:
public class JacksonIgnoreInherited {
public static class Base {
public final String field1;
public Base(final String field1) {
this.field1 = field1;
}
}
public static class Bean extends Base {
public final String field2;
public Bean(final String field1, final String field2) {
super(field1);
this.field2 = field2;
}
}
private static class IgnoreInheritedIntrospector extends JacksonAnnotationIntrospector {
#Override
public boolean hasIgnoreMarker(final AnnotatedMember m) {
return m.getDeclaringClass() == Base.class || super.hasIgnoreMarker(m);
}
}
public static void main(String[] args) throws JsonProcessingException {
final ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(new IgnoreInheritedIntrospector());
final Bean bean = new Bean("a", "b");
System.out.println(mapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(bean));
}
}
Output:
{
"field2" : "b"
}
You can override the superclass' methods which you'd like to prevent from being output and annotate them with #JsonIgnore. The override shifts the control of property creation to the subclass while enabling its ability to filter it from the output.
For instance:
public class SomeClass {
public void setField1(...);
public Integer getField1();
public void setField2(...);
public Integer getField2();
#Override
#JsonIgnore
public String superClassField1(...){
return super.superClassField1();
};
#Override
#JsonIgnore
public String superClassField2(...){
return super.superClassField2();
};
...
}
You can use this as well instead of unnecessary overrides
#JsonIgnoreProperties({ "aFieldFromSuperClass"})
public class Child extends Base {
private String id;
private String name;
private String category;
}
The good use of inheritance is that the child classes extend or add functionality. So the usual way is to serialize the data.
A workarround would be to use a Value Object (VO) or Data Transfer Object (DTO) with the fields you need to serialize. Steps:
Create a VO class with the fields that should be serialized.
Use BeanUtils.copyProperties(target VO, source data) to copy the properties
Serialize the VO instance.
Add the following annotation in your Base Class :
#JsonInclude(Include.NON_NULL)

JSON Parsing errors with RESTeasy/JAXB

I'm trying to make a call to the iTunes REST service that returns information about the genres defined in iTunes via a RESTeasy client. The JSON object returned by this call looks something like this:
{
"35":{
"name":"iPod Games",
"id":"35",
"url":"https://itunes.apple.com/us/genre/ipod-games/id35"
},
"36":{
"name":"App Store",
"id":"36",
"url":"https://itunes.apple.com/us/genre/ios/id36?mt=8"
}
}
I've defined my response object model like this:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#JsonIgnoreProperties(ignoreUnknown = true)
public class ITunesGenre implements Serializable {
private static final long serialVersionUID = 4330727214147295490L;
#XmlElement
private String name = null;
#XmlElement
private String id = null;
...
}
However, when I make the call via my RESTeasy client, however, I get serialization errors. I believe it is due to the fact that this is not a true List or array of objects. Instead, it seems like each entry has an "identifier" on it (in the example above, the "35" or "36").
Given a JSON object like this, how do I map this so that the RESTeasy client can deserialize it? I've not encountered objects of this format before. I obviously can't hard-code each identifier, since there will be several and they could potentially change.
You can see the full JSON object returned by this call (it's sizable) by clicking here. You'll see that this object structure is found throughout this object, rather than using simple Lists or Arrays of objects.
Any ideas? I'd really appreciate any help you can give.
The response is a Map so root element is not your ITunesGenre class but the Map.I suppose that it is clear how to modify response object.
I suppose it could look something like this (though i haven't tested it)
#XmlRootElement
public class Response implements Serializable
{
public Response(){
}
private java.util.Map<String, Genre> genres = new java.util.HashMap<String, Genre> ();
}
public class Genre implements Serializable {
private static final long serialVersionUID = 4330727214147295490L;
public Genre(){
}
#XmlElement
private String name = null;
#XmlElement
private String id = null;
...
}

Serialize own class

i'm experiencing some problems with the serialization of Java and haven't found my Error.
I want to serialize my class, save it and read it again. This is the class i want to serialize:
public class MusicItem implements Serializable {
private static final long serialVersionUID = 6429052113846297403L;
public String title;
public String album;
public String artist;
public String art;
public String musiclocation;
}
And when i want to write it i get the following error:
08-07 14:21:37.723: W/System.err(9557): java.io.NotSerializableException: de.godev.gomusic.MainActivity
I hope you can help me.
Thanks in Advance,
The class which is not getting serialized is de.godev.gomusic.MainActivity
Please post the source of MainActivity class as well
If MusicItem is an inner class, you should make it static. An inner class maintains a reference to the object that it's contained in, and if you try to serialize it, the containing object has to be serialized as well.
To make a nested class static declare it with the static keyword:
public static class MusicItem implements ...

JPA generic field

Is it possible to persist a generic field?
I have this property on an Entity class
...
private T payload;
...
T extends EventMessagePayload
and
public interface StringPayload extends EventMessagePayload{
String getPayload();
}
In my application i persist the field only when is of String type and during the save operation all works great.
When I read the object instead JPA try to create a String object but instead is a StringPaylod. Is there a way to intercept the creation and handle the object marshalling?
JPA itself does not allow this, but your JPA implementation might allow it. We once did this with Hibernate, and it boilds down to implement your own EntityTuplizer (and a HibernateInterceptor to map your objects back to HibernateEntities).
We can. if the T implements Serializable
#Entity
public class IgsSubject extends BasicObject implements Serializable{
private static final long serialVersionUID = -5387429446192609471L;

Categories