RestyGWT Polymorphic Encode/Decode issues when using an interface instead of an abstract class - json

According to RestyGWT documentation one must use an abstract super class for this to work, for instance, given:
#JsonSubTypes(#Type(value=PersonImpl.class, name="PersonImpl"))
#JsonTypeInfo(use=Id.NAME, include=As.PROPERTY, property="#class")
public abstract class Person{
public abstract String getName();
public abstract void setName(String name);
}
#JsonTypeName("PersonImpl")
public class PersonImpl extends Person{
private String name;
#Override
public final String getName() {
return name;
}
#Override
public final void setName(String name) {
this.name = name;
}
}
If I use the defined encoder/decoder this would work:
Person personInstance = new PersonImpl();
personInstance.setName("TestName");
PersonCodec codec = GWT.create(PersonCodec.class);
JSONValue json = codec.encode(personInstance);
Im trying to do something quite similar but with a small difference, that is, instead of Person being an abstract class I want it to be an Interface:
#JsonSubTypes(#Type(value=PersonImpl.class, name="PersonImpl"))
#JsonTypeInfo(use=Id.NAME, include=As.PROPERTY, property="#class")
public interface Person{
public String getName();
public void setName(String name);
}
For some reason this doesn't seem to work, as soon as I do that I start getting Errors when the JsonEncoderDecoder is generated. Has someone been able to achieve this?
Thanks!

Why not define your interface and make your abstract class implement it?

Related

How to deserialize json to an abstract class in spring-boot

In my Application i have something like this.
public class Question{}
public class MCQ extends Question{}
public class TrueAndFalse Question{}
public class Match Question{}
and in my RestController i have a service that adds question.
#RequestMapping(value = "/game/question/add", method = RequestMethod.POST)
public Question addQuuestion(#RequestParam("gameId") long id, #RequestBody Question question)
But i get an error when i try to call this service as i send json file with different structures one for MCQ, TrueAndFalse and Match.
so is it possible to deserialize the received json to Question abstract class.
And thanks in advance.
You can create a custom deserializer which will create Question instances based on json payload properties.
For example if the Question class looks like this:
public class Question {
private final String name;
#JsonCreator
Question(#JsonProperty("name") String name) {
this.name = name;
}
public String getName() {
return name;
}
}
And sub-class TrueAndFalse:
public class TrueAndFalse extends Question {
private final String description;
#JsonCreator
TrueAndFalse(#JsonProperty("name") String name,
#JsonProperty("description") String description) {
super(name);
this.description = description;
}
public String getDescription() {
return description;
}
}
Then you can create a deserializer, which will create an instance of TrueAndFale sub-class by checking if it has description property:
public class QuestionDeserializer extends JsonDeserializer<Question> {
#Override
public Question deserialize(JsonParser p, DeserializationContext ctx) throws IOException {
ObjectCodec codec = p.getCodec();
JsonNode tree = codec.readTree(p);
if (tree.has("description")) {
return codec.treeToValue(tree, TrueAndFalse.class);
}
// Other types...
throw new UnsupportedOperationException("Cannot deserialize to a known type");
}
}
And afterwards, make sure to register it on the object mapper:
#Configuration
public class ObjectMapperConfiguration {
#Bean
public ObjectMapper objectMapper() {
SimpleModule module = new SimpleModule();
module.addDeserializer(Question.class, new QuestionDeserializer());
return new ObjectMapper().registerModules(module);
}
}

Parsing map of object to a json

I've read countless articles about parsing Java objects to JSONs and still have issues...
I know that there are a bunch of frameworks out there and this is where things messed up I guess.
I'm trying to parse a map into a json:
Map<CategoryBean, Double> questionsPercentagePerCategory;
here's how CategoryBean looks like:
#XmlRootElement
public class CategoryBean implements Serializable{
private static final long serialVersionUID = -7306680546426636719L;
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
questionsPercentagePerCategory is a variable inside a wrapper json called: PrePracticeBean
and this is how it looks:
#XmlRootElement
public class PrePracticeBean implements Serializable {
private int maxQuestionsAllowedForUser;
private int maxQuestionsAllowedForUserAfterCreditOver;
private int questionsInExam;
#XmlJavaTypeAdapter(XmlGenericMapAdapter.class)
private Map<CategoryBean, Double> questionsPercentagePerCategory;
private static final long serialVersionUID = -655358519739911024L;
public int getMaxQuestionsAllowedForUser() {
return maxQuestionsAllowedForUser;
}
public void setMaxQuestionsAllowedForUser(int maxQuestionsAllowedForUser) {
this.maxQuestionsAllowedForUser = maxQuestionsAllowedForUser;
}
public int getMaxQuestionsAllowedForUserAfterCreditOver() {
return maxQuestionsAllowedForUserAfterCreditOver;
}
public void setMaxQuestionsAllowedForUserAfterCreditOver(int maxQuestionsAllowedForUserAfterCreditOver) {
this.maxQuestionsAllowedForUserAfterCreditOver = maxQuestionsAllowedForUserAfterCreditOver;
}
public int getQuestionsInExam() {
return questionsInExam;
}
public void setQuestionsInExam(int questionsInExam) {
this.questionsInExam = questionsInExam;
}
public Map<CategoryBean, Double> getQuestionsPercentagePerCategory() {
return questionsPercentagePerCategory;
}
public void setQuestionsPercentagePerCategory(Map<CategoryBean, Double> questionsPercentagePerCategory) {
this.questionsPercentagePerCategory = questionsPercentagePerCategory;
}
}
as you can see I've marked both beans with #XmlRootElement annotation to get Jeresey's OOB bean to JSON parsing functionality as specified here
Furthermore, here's how the XMLGenericMapAdapter looks like:
public class XmlGenericMapAdapter<K, V> extends XmlAdapter<MapType<K, V>, Map<K, V>> {
#Override
public Map<K, V> unmarshal(MapType<K, V> orgMap) throws Exception {
HashMap<K, V> map = new HashMap<K, V>();
for (MapEntryType<K, V> mapEntryType : orgMap.getEntries()) {
map.put(mapEntryType.getKey(), mapEntryType.getValue());
}
return map;
}
#Override
public MapType<K, V> marshal(Map<K, V> v) throws Exception {
MapType<K, V> mapType = new MapType<K, V>();
for (Map.Entry<K, V> entry : v.entrySet()) {
MapEntryType<K, V> mapEntryType = new MapEntryType<K, V>();
mapEntryType.setKey(entry.getKey());
mapEntryType.setValue(entry.getValue());
mapType.getEntries().add(mapEntryType);
}
return mapType;
}
}
Well, the end result is what makes me crazy... it's intermittent... when running the code in debug mode, this works flawlessly showing a nested json for the map and each key:value pair is another nested json. However, when invoked in run mode, I get an ugly "memory address" instead of the CategoryBean key...
My only guess is that this is related to class loading matters and that I might be having some other JAR that's having a class which is loaded first in debug mode but not in run mode...
anyways, any suggestions as to how this should be done, would be appreciated.
thanks,
GBa.
Well, solved...
some JAXB/Jersey stuff which I'm not into understanding up to the last bit... but I bet that there's some JAXB guru out there who could give the right explanation why this is the case...
Anyways, bottom line is that the CategoryBean class should not have the annotation #XmlRootElement but instead should have #XmlAccessorType(XmlAccessType.FIELD)
I got the inspiration for that from Serializer for (Hash)Maps for Jersey use?
thanks,
GBa.

GWT Autobean without setter method

I am using Autobean framework to encode/decode JSON in my GWT application. It works in cases with the interfaces having getters and setters. But is there any way to do it some other way to do this without specifying a setThisCollectionProperty instead using an addToThisCollectionProperty method?
For example, I have an interface IPerson like this:
public interface IPerson {
public String getName();
public void setName(String name);
public int getAge();
public void setAge(int age);
public List<String> getIds();
public void addId(String id);
}
BeanFactory is like this:
public interface BeanFactory extends AutoBeanFactory {
public AutoBean<IPerson> person();
public AutoBean<IPerson> person(IPerson person);
}
and in Person class which implements IPerson,
public class Person implements IPerson {
private String name;
private List<String> ids;
...
public List<String> getIds() {
return ids;
}
public void addId(String id) {
...
ids.add(id);
}
}
It works if the addId(String id) is replaced with setIds(List<String> ids).
Otherwise the following error is shown:
The com.mycompany.jsonsample.beans.IPerson parameterization is not simple, but the person method does not provide a delegate
Is it possible to encode/decode without a set method?
AutoBean manages all getters and setters, and only getters and setters. For any other method, you have to use a category.
Using a category, you could thus implement addId(…) as getIds().add(…), or possibly directly call addIds on the underlying object if the AutoBean is a wrapper.

How to store the same entity in mulitple lists in Hibernate using JPA

Im very new to Hibernate so this will probably a easy task for you guys.
As the Topic says I'm trying to reference the same entity in multiple Lists. But when I try to do so I get an exception saying: "Duplicate entry '5' for key 'military_id'".
I googled but could not find a solution to my problem.
I have an Entity called MilitaryUnitData like this:
#Entity
public class MilitaryUnitData implements IMovable{
private long Id;
//snip
#Id
#GeneratedValue(strategy=GenerationType.TABLE)
public long getId() {
return Id;
}
public void setId(long id) {
Id = id;
}
//snip
}
and a class City where I want to store my units in.
#Entity
public class CityData {
private Collection<MilitaryUnitData> military = new ArrayList<MilitaryUnitData>();
private String name;
//snip
#Id
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#OneToMany
#Column(nullable=false)
public Collection<MilitaryUnitData> getMilitary() {
return military;
}
public void setMilitary(Collection<MilitaryUnitData> military) {
this.military = military;
}
//snip
}
The problem occurs when I want to put a Unit into 2 cities at the same time.
How do I have to change the mapping to achive this?
Thx in advance.
I'm trying to reference the same entity in multiple Lists
After looking at your code, I think you mean, that the same MilitaryUnitData is used in several CityData?
IF this is correct, than the realtion ship is a M:N relation ship, and you need to use a #ManyToMany instead of an #OneToMany.

JEE6 - #ApplicationException - #Inject and #PostConstruct not called

I have a problem with #Inject and #PostConstruct method not called in a #ApplicationException annoted class. I'm using Glassfish 3.0.1 with JPA,CDI and EJBs in the service(=ejb)-layer and would like to throw an errorMessage that contains a text in the sessionlanguage.
I have an abstract ExceptionClass
public abstract class LocalizedException extends Exception {
private static final long serialVersionUID = 1L;
String localizedMessage;
//This method should be called as #PostConstruct from the concrete classe
protected void setLocalizedMessage(LocaleHandler localeHandler, String key){
this.setLocalizedMessage(localeHandler, key, new Object());
}
protected void setLocalizedMessage(LocaleHandler localeHandler, String key, Object... args){
localizedMessage = ErrorMessages.getErrorMessage(key,localeHandler.getAktuelleLokale(),args);
}
#Override
public String getMessage() {
return localizedMessage;
}
#Override
public String getLocalizedMessage() {
return localizedMessage;
}}
And a concrete class:
#ApplicationException
public class ConcreteException extends LocalizedException {
private static final long serialVersionUID = 2615388267911318734L;
private int userId;
public ConcreteException(int userId) {
this.userId=userId;
}
public int getUserId() {
return userId;
}
#PostConstruct
#Inject
public void initText(LocaleHandler localeHandler){
setLocalizedMessage(localeHandler, "msgKey");
}
}
The LocaleHandler (=Sessionscoped) should be injected to provide the currentLocale which is used to retrieve an errormessage from a bundle.
The problem is, that the #PostConstruct is never called no matter what I try. I even annoted the concrete class with #Named, used #Inject in the concrete class instead of the abstract, but nothing works. When I call initText() directly I can see (in the debugger), that the LocaleHandler is not injected.
Now I'm asking myself if there is a restriction regarding Exception classes and CDI or did I simply not find the source of the problem !
Do you know the answer ?
thanx in advance
Thomas
The problem is solved.
I simply used the Exception as throw new ConcreteException(), as I'm used to since ages. Excactly this was the problem. Now I inject the ConcreteException into my EJB and throw the containercreated field. This way #Inject and #Postconstruct are working !