Override swagger discerption/example using #ApiModelProperty in the inherited class fields - java

I have two classes
public class Account {
#ApiModelProperty(example = "EUR")
private CurrencyCode currency;
....// public setters and getters
}
and
public class SpecificAccount extends Account {
//Here I need to override the currencie example without redefining the currency field
#ApiModelProperty(example = "USD")
private CurrencyCode currency;
}
Can we override swagger discerption/example using #ApiModelProperty in inherited class ?

You should add #ApiModel annotations, also classes should have getters for all fields you want to have documented.
If you have only getters, then args constructor is required, in case you have getters and setters then default one is enough.
#ApiModel(subTypes = {SpecificAccount.class})
public class Account {...}
#ApiModel(parent = Account.class)
public class SpecificAccount extends Account {...}

Related

Jackson Deserialize Polymorphic Wrapper With Polymorphic Member

I have a parent wrapper class that I need to use to transport data between our systems in a unified format, and I need to be able to deduce the sub-type of it. I was able to make this work with a custom deserializer, but I've been tasked with re-implementing it based on annotations. I've gotten partway there, but I'm hitting an InvalidDefinitionException now that I think stems from Jackson looking for a 1-String constructor to my inner type, instead of using the #JsonCreator all-args constructor that used to work before with my Deserializer.
There should be a way to have the TypeInfo and SubTypes cascade down the hierarchy, even with a wrapper/holder type, right?
Wrapper Classes:
#JsonTypeInfo(use=JsonTypeInfo.NAME, property="type", visible=true)
#JsonSubTypes({
#JsonSubTypes.Type(value=UserApiMessage.class, name=UserPayloadNameEnum.Constant.LOGIN),
#JsonSubTypes.Type(value=UserApiMessage.class, name=UserPayloadNameEnum.Constant.CONFIG_REQUEST),
#JsonSubTypes.Type(value=SystemApiMessage.class, name=SystemPayloadNameEnum.Constant.METRICS_REQUEST),
#JsonSubTypes.Type(value=SystemApiMessage.class, name=SystemPayloadNameEnum.Constant.METRICS_RESPONSE),
...
})
public abstract class ApiMessage {
public abstract String getRequestId();
public abstract Enum getType(); //Object mapper de/serializes on Enum.name
public abstract ApiPayload getPayload();
}
public class UserApiMessage extends ApiMessage {
private final String requestId;
private final UserPayloadNameEnum type;
#JsonTypeInfo(use=JsonTypeInfo.NAME, include=JsonTypeInfo.As.EXTERNAL_PROPERTY, property="type", visible=true)
#JsonSubTypes({
#JsonSubTypes.Type(value=Login.class, name=UserPayloadNameEnum .Constant.LOGIN),
#JsonSubTypes.Type(value=ConfigRequest.class, name=UserPayloadNameEnum.Constant.CONFIG_REQUEST)
})
private final UserPayload payload;
//All-Args #JsonCreator constructor
//All #Override getters
}
public class SystemApiMessage extends ApiMessage {
private final String requestId;
private final SystemPayloadNameEnum type;
#JsonTypeInfo(use=JsonTypeInfo.NAME, include=JsonTypeInfo.As.EXTERNAL_PROPERTY, property="type", visible=true)
#JsonSubTypes({
#JsonSubTypes.Type(value=MetricsRequest.class, name=SystemPayloadNameEnum .Constant.METRICS_REQUEST),
#JsonSubTypes.Type(value=MetricsResponse.class, name=SystemPayloadNameEnum .Constant.METRICS_RESPONSE)
})
private final SystemPayload payload;
//All-Args #JsonCreator constructor
//All #Override getters
}
A parent ApiPayload class, which is polymorphic
public abstract class ApiPayload {
...
}
public abstract class UserPayload extends ApiPayload {
...
}
public abstract class SystemPayload extends ApiPayload {
...
}
And their concrete implementations.
public class Login extends UserPayload {
//All-Args #JsonCreator as constructor
}
public class ConfigRequest extends UserPayload {
//All-Args #JsonCreator as constructor
}
public class MetricsRequest extends SystemPayload {
//All-Args #JsonCreator as constructor
}
public class MetricsResponse extends SystemPayload {
//All-Args #JsonCreator as constructor
}
When executing mapper.readValue(json, ApiMessage.class); on a well-formed "Login" request that worked with my old custom deserializer, I get the following error.
InvalidDefinitionException: Cannot construct instance of 'com.foo.bar...UserApiMessage', problem: argument type mismatch.
at(Source: (String)" {
My well-formed json
}"; line 15, column: 1]
So if I'm reading this correctly, Jackson is looking for a 1-string constructor of UserApiMessage, rather than continuing the type deduction. What am I doing wrong?
Side Note: if I add the #JsonTypeInfo with WRAPPER_OBJECT and repeat the SubTypes on the class signature for UserPayload, I actually get to the point it tries to construct a Login object, but then all of the args are missing (given default/null values).

How to declare a variable or Object of any class type in Java

I am quite new to Java and I am trying to deserialize the JSON using Jackson and I facing some minor issue with regards to declaring the Object/Variable type. I will provide all the codes then explain the issue for easy understanding.
I have an enum that will have the required type values:
public enum IdentifierTypeValues {
Type1,
Type2,
Type3,
//Constructor and Getter of enum values
}
Then for each of these type, I have different classes which will have different input and do a completely different type of process:
public class GenerateType1 {
private String name;
private String age;
//Getter and Setter
//Some required process based on these values
}
public class GenerateType2 {
private String address;
private String city;
private String country;
//Getter and Setter
//Some required process based on these values
}
public class GenerateType3 {
private String firstName;
private String lastName;
private String fullName;
//Getter and Setter
//Some required process based on these values
}
Now I have a wrapper class for these type of classes which will take the type based on enum and typeInfo values. I want the typeInfo values to be any of the class based type something like this:
public class TypeSyntax {
private IdentifierTypeValues indeitiferType;
private GenerateType1 / GenerateType2 / GenerateType3 identifierTypeValues;
//Here the identifierTypeValues can have the values for anytype
//How to declare a variable of any of these class type?
}
This is the class that will be used by my JSON for deserializing. I know I can add a wrapper class of those 3 types and provide that wrapper class as a type class for this. Something like this:
public class WrapperClass{
private GenerateType1 type1;
private GenerateType2 type2;
private GenerateType3 type3;
}
public class TypeSyntax{
private IdentifierTypeValues indeitiferType;
private WrapperClass identifierTypeValues;
//But using this approach will change my JSON structure which I do not want to do.
}
My JSON structure is something like this and I would like to keep it in the same way.
{
"indeitiferType":"Type1",
"identifierTypeValues":{
"name":"Batman",
"age":"2008"
}
}
Is there a way I can declare the variable of multiple type class? or any better approach to handle this by keeping the json format same? I tried searching but I am unable to search what exactly so any help would be really appriciated.
Because the type identifier exists on a different level than the other properties a wrapper class TypeSyntax needed. There are several open feature requests to add wrapping functionality to Jackson e.g. https://github.com/FasterXML/jackson-databind/issues/512
Fortunately polymorphism is supported in Jackson with #JsonTypeInfo and #JsonSubTypes annotations.
Wrapper class should look like:
public class TypeSyntax {
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "identifierType")
private GenerateTypeBase identifierTypeValues;
// getters and setters (omitted for brevity)
}
GenerateTypeBase is the common parent class
#JsonSubTypes({
#JsonSubTypes.Type(value = GenerateType1.class, name = "Type1"),
#JsonSubTypes.Type(value = GenerateType2.class, name = "Type2"),
})
public abstract class GenerateTypeBase {
private String name;
private String age;
// getters and setters (omitted for brevity)
}
In this different children classes will instantiated based on the identifierType property.
The children must extend this base class:
public class GenerateType2 extends GenerateTypeBase {
// additional properties
}
In a short test it will be:
#Test
void wrapperTest() throws IOException {
ObjectMapper mapper = new ObjectMapper();
GenerateType2 a = new GenerateType2();
a.setName("Foo");
a.setAge("13");
TypeSyntax w = new TypeSyntax();
w.setIdentifierTypeValues(a);
String json = mapper.writeValueAsString(w);
System.out.println(json);
}
and the output:
{
"identifierTypeValues":
{
"name":"Foo",
"age":"13"
},
"identifierType":"Type2"
}
Deserialization
#Test
void wrapperTest() throws IOException {
ObjectMapper mapper = new ObjectMapper();
String input = "{\"identifierTypeValues\": \"name\":\"Foo\",\"age\":\"13\"},\"identifierType\":\"Type2\"}";
TypeSyntax w = mapper.readValue(new StringReader(input), TypeSyntax.class);
assertAll(
() -> assertEquals(GenerateType2.class, o.getIdentifierTypeValues().getClass()),
() -> assertEquals("13", o.getIdentifierTypeValues().getAge())
);
}
If you want more flexibility you can write custom (de)serializer and / or custom resolver. Using custom TypeIdResolver that will possible to convert identifiers to types programmatically instead of using "key-value pairs" in #JsonSubTypes

How to add custom deserializer to interface using jackson

Saying I have an interface A, I want to use custom deserializer for all classes implement interface A, So I use code below but it doesn't work, While CustomAserializer works.
So what should I do to deserialize all classes implement A using my custom deserializer.
Thanks.
module.addDeserializer(A.class, new CustomADeserializer());
module.addSerializer(A.class, new CustomASerializer())
It seems you forgot to annotate your implementation classes with #JsonDeserialize(using = ImplementationClazz.class) to indicate that the class should be used to deserialize the abstract class or interface.
The following is a simple example to deserialize an interface having multiple implementations using Jackson.
Here is my interface:
#JsonDeserialize(using = UserDeserializer.class)
public interface User {
}
One implementation of the interface:
#JsonDeserialize(as = ServiceUser.class)
public class ServiceUser implements User{
private String name;
private String role;
//constructor, setters & getters
Second implementation:
#JsonDeserialize(as = AdminUser.class)
public class AdminUser implements User {
private String role;
private String designation;
//constructor, setters & getters
And here is the deserializer:
public class UserDeserializer extends JsonDeserializer<User> {
#Override
public User deserialize(JsonParser jp, DeserializationContext context) throws IOException {
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
ObjectNode root = mapper.readTree(jp);
/*write your own condition*/
if (root.has("name") && root.get("name").asText().equals("XYZ")) {
return mapper.readValue(root.toString(), ServiceUser.class);
}
return mapper.readValue(root.toString(), AdminUser.class);
}
}
You may get a StackOverflowError if you don't annotate the implementation classes. All implementation classes should deserialize themselves, otherwise it will use the deserializer from the parent class which leads to a StackOverflowError.
Just in case someone need a solution to serialize and desiralize inheritance hierarchy
you can use jackson annotation in more elegant way : JsonTypeInfo and JsonSubTypes
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
#JsonSubTypes({
#Type(value = ServiceUser.class, name = "service"),
#Type(value = AdminUser.class, name = "admin")
})
public interface User{
// ...
}

Javax validation, validate an object's property with annotations

Let's say I have the following classes :
public class MyProductCode {
private String code;
// getter and setter
}
public class MyProduct {
#NotNull
private MyProductCode myCode;
// getter and setter
}
Is it possible to validate the "code" property via the "MyProduct" class ?
Something like this :
#NotNull(property = "code")
private MyProductCode myCode;
Using Oval framework, it would be possible:
Refer Declaring constraints for nested properties

Problem persisting inheritance tree

I have a problem trying to map an inheritance tree. A simplified version of my model is like this:
#MappedSuperclass
#Embeddable
public class BaseEmbedded implements Serializable {
#Column(name="BE_FIELD")
private String beField;
// Getters and setters follow
}
#MappedSuperclass
#Embeddable
public class DerivedEmbedded extends BaseEmbedded {
#Column(name="DE_FIELD")
private String deField;
// Getters and setters follow
}
#MappedSuperclass
public abstract class BaseClass implements Serializable {
#Embedded
protected BaseEmbedded embedded;
public BaseClass() {
this.embedded = new BaseEmbedded();
}
// Getters and setters follow
}
#Entity
#Table(name="MYTABLE")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="TYPE", discriminatorType=DiscriminatorType.STRING)
public class DerivedClass extends BaseClass {
#Id
#Column(name="ID", nullable=false)
private Long id;
#Column(name="TYPE", nullable=false, insertable=false, updatable=false)
private String type;
public DerivedClass() {
this.embedded = new DerivedClass();
}
// Getters and setters follow
}
#Entity
#DiscriminatorValue("A")
public class DerivedClassA extends DerivedClass {
#Embeddable
public static NestedClassA extends DerivedEmbedded {
#Column(name="FIELD_CLASS_A")
private String fieldClassA;
}
public DerivedClassA() {
this.embedded = new NestedClassA();
}
// Getters and setters follow
}
#Entity
#DiscriminatorValue("B")
public class DerivedClassB extends DerivedClass {
#Embeddable
public static NestedClassB extends DerivedEmbedded {
#Column(name="FIELD_CLASS_B")
private String fieldClassB;
}
public DerivedClassB() {
this.embedded = new NestedClassB();
}
// Getters and setters follow
}
At Java level, this model is working fine, and I believe is the appropriate one. My problem comes up when it's time to persist an object.
At runtime, I can create an object which could be an instance of DerivedClass, DerivedClassA or DerivedClassB. As you can see, each one of the derived classes introduces a new field which only makes sense for that specific derived class. All the classes share the same physical table in the database. If I persist an object of type DerivedClass, I expect fields BE_FIELD, DE_FIELD, ID and TYPE to be persisted with their values and the remaining fields to be null. If I persist an object of type DerivedClass A, I expect those same fields plus the FIELD_CLASS_A field to be persisted with their values and field FIELD_CLASS_B to be null. Something equivalent for an object of type DerivedClassB.
Since the #Embedded annotation is at the BaseClass only, Hibernate is only persisting the fields up to that level in the tree. I don't know how to tell Hibernate that I want to persist up to the appropriate level in the tree, depending on the actual type of the embedded property.
I cannot have another #Embedded property in the subclasses since this would duplicate data that is already present in the superclass and would also break the Java model.
I cannot declare the embedded property to be of a more specific type either, since it's only at runtime when the actual object is created and I don't have a single branch in the hierarchy.
Is it possible to solve my problem? Or should I resignate myself to accept that there is no way to persist the Java model as it is?
Any help will be greatly appreciated.
Wow. This is the simplified version? I assume that the behavior that you are seeing is that BaseEmbedded field is persisted but not the FIELD_CLASS_A or B?
The problem is that when Hibernate maps the DerivedClassA and B classes, it reflects and sees the embedded field as a BaseEmbedded class. Just because you then persist an object with the embedded field being a NestedClass, the mapping has already been done and the FIELD_CLASS_A and B are never referenced.
What you need to do is to get rid of the NestedClass* and embedded field and instead have the fieldClassA and B be normal members of DerivedClassA and B. Then add add a name field to the #Entity which will put them both in the same table I believe. This will allow you to collapse/simplify your class hierarchy a lot further.
See: http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e1168
#Entity(name = "DerivedClass")
#DiscriminatorValue("A")
public class DerivedClassA extends DerivedClass {
#Column(name="FIELD_CLASS_A")
private String fieldClassA;
...
#Entity(name = "DerivedClass")
#DiscriminatorValue("B")
public class DerivedClassB extends DerivedClass {
#Column(name="FIELD_CLASS_B")
private String fieldClassB;
...

Categories

Resources