Inheriting #JsonCreator annotations from Superclass - java

I have a number of objects with a set of shared properties in a superclass:
public Superclass {
int id;
String name;
...
}
And I have subclasses which inherit from the superclass but each of them need their own fully-described #JsonCreator
public Subclass1 extends Superclass {
String color;
#JsonCreator
public Subclass1(#JsonProperty("id") int id,
#JsonProperty("name") String name,
#JsonProperty("color") String color)
{
super(id, name);
this.color = color;
}
}
public Subclass2 extends Superclass {
int height;
#JsonCreator
public Subclass1(#JsonProperty("id") int id,
#JsonProperty("name") String name,
#JsonProperty("height") int height)
{
super(id, name);
this.height = height;
}
}
Is there any way for Jackson (2.x) to pull information from the superclass regarding expected JSON fields and to avoid this repetition?

Since your classes do not appear to be immutable you could put #JsonSetter annotations on setter methods in the base class for the "id" and "name" properties. Then deserialization will create the appropriate subtype and use the setters instead of a constructor.
public class Superclass {
private int id;
private String name;
#JsonSetter
public void setId(int id) { ... }
#JsonSetter
public void setName(String name) { ... }
}
public Subclass1 extends Superclass {
private String color;
#JsonSetter
public void setColor(String color) { ... }
}
public Subclass2 extends Superclass {
private int height;
#JsonSetter
public void setHeight(int height) { ... }
}
You might be able to use #JsonSubTypes as well. This annotation would go on Superclass and you would have to list references to each subtype (Subclass1 and Subclass2). I don't know off the top of my head if this would allow you to leverage a #JsonCreator in Superclass to avoid repeating the "id" and "name" properties in the subclasses but I figure it's worth a try. The down side of this approach is that your base class has explicit references to subtypes.

Related

Error when extending from abstract parent class

Error
public Cat (String nm, int legs, String sd, String col)
For this constructor I got following compiler error:
constructor Animal in class Animal cannot be applied to given types;
required: String, int
found: no arguments
reason: actual and formal arguments lists differ in length
Code
The parent class is right below the child class.
public class Cat extends Animal {
private String sound;
private String colour;
public Cat (String nm, int legs, String sd, String col) {
nm = super.getName();
legs = super.getNumOfLegs();
sound = sd;
colour = col;
}
public abstract class Animal {
protected String name;
protected int numOfLegs;
public Animal() {
}
public Animal(String nm, int legs) {
name = nm;
numOfLegs = legs;
}
public String getName() {
return name;
}
public int getNumOfLegs() {
return numOfLegs;
}
public abstract String display();
}
}
Should the parent abstract class be placed in a separate file instead?
I've tried that initially but it returned way more errors than it did now, especially from the abstract method display().
What is causing the error?
There are a couple of things you should change.
First of all, it is the best way to put the super class into a separate file. If you want to keep in one file you need drag it out of the Cat class and remove the scope (not public or private). But this is not a good coding style for a super class.
The next thing is, with the name/nm and legs/numOfLegs. Either you call the super constructor and provide the two variables (see my example) or you use name = nm; and numOfLegs = legs;
You should also reconsider if the name and numOfLegs varialbes need to be protected or if is fine to provide the access only through the getter.
If the number of legs, the name, sound and color will not change you could also make them immutable (with the key word final, e.g. private final String sound). If not you can make them accessible with a setter.
Finally you need to implement the abstract method in the Cat class...
public class Cat extends Animal {
private String sound;
private String colour;
public Cat(String nm, int legs, String sd, String col) {
super(nm, legs);
sound = sd;
colour = col;
}
#Override
public String display() {
return null;
}
}
abstract class Animal {
protected String name;
protected int numOfLegs;
public Animal(String nm, int legs) {
name = nm;
numOfLegs = legs;
}
public String getName() {
return name;
}
public int getNumOfLegs() {
return numOfLegs;
}
public abstract String display();
}

How to Call a Subclass Method From a SuperClass Object

lets suppose i have this Parent Class
public abstract class Parent
{
private String name;
private String surname;
public Parent(String name, String surname)
{
this.name=name;
this.surname=surname;
}
and lets suppose i have many child classes like that and everyone of them has it's own different attributes to add to their parent ones
public class Child extends Parent
{
private String favColor;
public Child(String name,String surname,String favColor)
{
super(name,surname);
this.favColor=favColor;
}
public getFavColor()
{
return this.favColor
}
now i'm in this situation
Parent parent = new Child(name,surname,favColor);
and what i want to do is calling the method getFavColor() on the object parent like this
parent.getFavColor();
is this working? i guess not, so how could i be able to call such method on such object? i thought of declaring abstract getters of childs attributes on the superclass but that doesn't sound very prone to the open/closed principle, because in a time in future when i will want to add more child-like classes i will have to declare every getters of the child attributes in the superclass which is not supposed to know about his childrens.
thank you very much :)
In this case you can't call the getFavColor() method. The method is defined only in Child class and your reference is Parent. For this, is necessary the definition the getFavColor() method in Parent Class.
You would create a abstract method fav() in Parent class:
public abstract class Parent
{
private String name;
private String surname;
public Parent(String name, String surname)
{
this.name=name;
this.surname=surname;
}
public abstract String fav();
}
So called:
parent.fav();
Thus, you can implement the method in different ways on your children, such as:
public class Child extends Parent
{
private String favColor;
public Child(String name,String surname,String favColor)
{
super(name,surname);
this.favColor=favColor;
}
public String fav()
{
return this.favColor;
}
}
And:
public class SecondChild extends Parent
{
private String favSport;
public Child(String name,String surname,String favColor)
{
super(name,surname);
this.favColor=favColor;
}
public String fav()
{
return this.favSport;
}
}
Use this only if the signature of methods are equals in all children (in your case, if all children methods return a String).
You would need an abstract method to do that. Your parent is already abstract so that's good. It would go something like this:
public abstract class Parent {
private String name;
private String surname;
public Parent(String name, String surname) {
this.name = name;
this.surname = surname;
}
public void showFavColor() {
system.print.ln(this.getFavColor());
}
abstract string getFavColor();
}
public class Child extends Parent {
private String favColor;
public Child(String name, String surname, String favColor) {
super(name, surname);
this.favColor = favColor;
}
#Override
public String getFavColor() {
return this.favColor
}
}
Every child of the parent MUST extends the abstract function. Since the function is technically declared in the parent, it is accessible from it.
This means, you could do
Parent parent = new Child(name,surname,favColor);
parent.showFavColor();

jackson serialization of nested objects

I have problem with jackson serialization of object by its interface.
I have class
class Point implements PointView {
private String id;
private String name;
public Point() {
}
public Point(String id, String name) {
this.id = id;
this.name = name;
}
#Override
public String getId() {
return id;
}
public String getName() {
return name;
}
}
which implements
interface PointView {
String getId();
}
and have class
class Map implements MapView {
private String id;
private String name;
private Point point;
public Map() {
}
public Map(String id, String name, Point point) {
this.id = id;
this.name = name;
this.point = point;
}
#Override
public String getId() {
return id;
}
public String getName() {
return name;
}
#JsonSerialize(as = PointView.class)
public Point getPoint() {
return point;
}
}
which implements
interface MapView {
String getId();
Point getPoint();
}
And have class
class Container {
private Map map;
public Container() {
}
public Container(Map map) {
this.map = map;
}
#JsonSerialize(as = MapView.class)
public Map getMap() {
return map;
}
}
I want serialize Container with Jackson and get result
{"map":{"id":"mapId","point":{"id":"pointId"}}}
But in fact I get result
{"map":{"id":"mapId","point":{"id":"pointId","name":"pointName"}}}
that have property "name" in nested object "point" although I specified serializition type of Point in Map (#JsonSerialize(as = PointView.class)). Interface PointView dont have method getName, but in result exists field "name" of Point.
If I remove annotation (#JsonSerialize(as = MapView.class)) from method getMap in class Container I get result
{"map":{"id":"mapId","name":"mapName","point":{"id":"pointId"}}}
Now point dont have property "name", but map have.
How can I get result
{"map":{"id":"mapId","point":{"id":"pointId"}}}
?
To get the desired result also the same method in interface must be annotated by #JsonSerialize
interface MapView {
String getId();
#JsonSerialize(as = PointView.class)
Point getPoint();
}
You can annotate the method like this:
#JsonIgnore
public String getName() {
return name;
}
Or if you want specific serialization in this use case, but normal serialization in others, you can use a #JsonView (see doc).
The reason it's serializing out the name is that the instance has the accessor getName(), even though interface does not.
Yes, you can use
#JsonSerialize(as=MyInterface.class)
public class ConcreteClass implements MyInterface { .... }
either on implementation class (as above), or on property that has value.

How to convert an object from class to superclass

I have to model breakwater that controls permissions in certain coast. My solution implements a class "Ship" and classes "OilShip", "FishingShip" and "CarriageShip", I used inheritance and made
public class OilShip extends Ship{
...
}
public class FishingShip extends Ship{
...
}
public class CarriageShip extends Ship{
...
}
In another class I have Ship ship=new Ship(...); and I'd like to somehow make an Oilship into Ship, i.e.
public Class Abcd{
Ship ship;
public Abcd(OilShip oship){
ship=oship; //*************
}
}
There seems to be a problem with the code, please tell me.
Make sure you call the superclass' constructor inside your subclasses' constructors.
This solution works fine for me:
public class Ship {
private String name;
private int weight;
public Ship(String name, int weight) {
this.name = name;
this.weight = weight;
}
}
class OilShip extends Ship {
private int oilCapacity;
public OilShip(int oilCapacity, String name, int weight) {
super(name, weight);
this.oilCapacity = oilCapacity;
}
}
class FishingShip extends Ship {
private int fisherMen;
public FishingShip(int fisherMen, String name, int weight) {
super(name, weight);
this.fisherMen = fisherMen;
}
}
class CarriageShip extends Ship {
private int containers;
public CarriageShip(int containers, String name, int weight) {
super(name, weight);
this.containers = containers;
}
}
As mentioned before, Java-classes should always be given a name, where the first character is in UPPERCASE and the same with each new word --> CamelCase
You don't need different constructors. The awesome thing behind using inheritance here, is, that no matter what subclass from the superclass "Ship" you put into your constructor in "abcd", it will be accepted:
public class Abcd {
private Ship ship;
public Abcd(Ship ship){
this.ship = ship;
}
}

Programming difference between POJO and Bean

I have the following two classes. Can I say the first one is a POJO class and the second one as a Bean class?
1) POJO class, since it has only getter and setter method, and all the member are declared as private
public class POJO {
private int id;
private String name;
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setId() {
this.id = id;
}
public void setName() {
this.name = name;
}
}
2) Bean class - all the member variables are private, has getters and setters and implements Serializable interface
public class Bean implements java.io.Serializable {
private String name;
private Integer age;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return this.age;
}
public void setAge(Integer age) {
this.age = age;
}
}
It also has a no-arg constructor.
Only difference is bean can be serialized.
From Java docs - http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html
Serializability of a class is enabled by the class implementing the java.io.Serializable interface. Classes that do not implement this interface will not have any of their state serialized or deserialized. All subtypes of a serializable class are themselves serializable. The serialization interface has no methods or fields and serves only to identify the semantics of being serializable.
the JavaBean class must implement either Serializable or Externalizable, must have a no-arg constructor,all JavaBean properties must public setter and getter methods (as appropriate)
all JavaBean instance variables should be private

Categories