I have 2 classes
public class A {
protected String id;
}
And
public class B extends A {
private String bval;
}
The JSON we recieve for class B has the id with a different name, is there are way to tell jackson to use a different property name for id in classB than in classA?
Obe way to do it is to use the "any setter" feature, where Jackson is told to call a method for all "unknown" properties. You can then do the assignment yourself:
public class B extends A {
// all unknown properties will go here
#JsonAnySetter
public void setUnknownProperty(String key, Object value) {
if (key.equals("anotherNameForId")) {
id = (String)value;
}
}
I was using lombok
#Getter(onMethod = #__( #JsonProperty("id")))
and in class B
#Override
#JsonProperty("bID")
public String getId(){
return this.id;
}
Related
I have a class A (listed below) which can have many different types of attributes saved to it. Naturally these attributes can be of different types. Based on the type of attribute I want to apply some validations to it.
What would be the best way of doing it in Micronaut?
Here is an example of what I want to achieve:
public class A {
private String type;
private String value;
// getter/setter omitted…
}
Some example instances of class A:
{type: "type1", value: "examplevalue1"}
{type: "type2", value: "examplevalue2"}
{type: "type2", value: "examplevalue3"}
Then I have some set of validation rules which are relevant to the respective types. Each type (type1, type2, type3) have separate set of validation rules. These rules are not just restricted to String validation but also semantic and business validation.
I would solve this using specific class per type. You can introduce an interface A
interface A {
String getType();
}
and then implement the concrete types.
public class Type1 implements A {
#NotBlank
private String value;
#Override
public String getValue() { return this.value; }
public void setValue(String v) { this.value = v; }
}
public class Type2 implements A {
#YourCustomValidator
private String value;
#Override
public String getValue() { return this.value; }
public void setValue(String v) { this.value = v; }
}
and then implement a custom Jackson Deserializer which is able to build an instance of A by inspecting the JSON string field type.
I don't think that Drools has anything to do with this question.
I am using java w/ Jackson and would like to use a string prefix as my type for deserialization and the java pojo for generating that prefix at serialization.
class A implements TopLevel {
String id;
public String getPrefix() {
return "aPrefix"
}
}
class B implements TopLevel {
String id;
public String getPrefix() {
return "bPrefix"
}
}
interface TopLevel {
String getPrefix()
}
//This should create an instance of A w/ Id = "423412421421412RandomId"
mapper.readValue("aPrefix.423412421421412RandomId", TopLevel.class)
//This should create an instance of A w/ Id = "OtherRandomId"
B b = mapper.readValue("bPrefix.OtherRandomId", TopLevel.class)
//This should create string "bPrefix.OtherRandomId"
mapper.writeValue(b)
Ideally I would like to be able to define the following, and use #JsonSubTypes or the most standard Jackson way possible to be able to create these value type strings.
Initial Question
Is it possible to have multiple #JsonCreator methods, and for jackson to detect which one it should use depending on the method definiton?
#JsonCreator
public static StateOfComm factory(String id) {
return StateOfComm.valueOf(id);
}
#JsonCreator
public static StateOfComm factory(CustomType value) {
return StateOfComm.valueOf(value.getId());
}
Update
The JSON that fails (because id=null), is the following:
{"comment":null, "processes":[{"stateOfComm":{"id":"CA"}}]}
The following works:
{"comment":null, "processes":[{"stateOfComm":"CA"}]}
I was able to parse both JSON examples in your question by:
using jackson-modules-java8 version 2.9.1 dependency
invoking the java 8 compiler with -parameters argument
introducing all argument constructors for all classes involved
avoiding #JsonProperty on static creation methods and constructors
defining a class:
class CustomType {
private final String id;
}
My understanding is that Jackson couldn't discern between multiple creators in older version. E.g. see answer here and github issue here. It seems that the option to have parameter names in compiled code in java 8 helps in this case.
I solved this problem by getting rid of the #JsonCreator annotations, and using a custom StdDeserializer that did the trick.
Here is an example:
#JsonIgnoreProperties(
ignoreUnknown = true
)
#JsonDeserialize(
using = IdTextEntry.Deserializer.class
)
#Data
public class IdTextEntry implements IdAndText {
String id;
String text;
public IdTextEntry(Enum<?> val) {
if (val != null) {
this.id = val.name();
this.text = val.toString();
}
}
public static class Deserializer extends StdDeserializer<IdTextEntry> {
public Deserializer() {
this((Class)null);
}
Deserializer(Class<?> vc) {
super(vc);
}
public IdTextEntry deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
JsonNode node = (JsonNode)jp.getCodec().readTree(jp);
String id;
if (node.has("id") && node.has("text")) {
id = node.get("id").asText();
String text = node.get("text").asText();
return new IdTextEntry(id, text);
} else if (node.has("id")) {
id = node.get("id").asText();
return new IdTextEntry(id, id);
} else {
id = node.asText();
return new IdTextEntry(id, id);
}
}
}
}
You can have multiple #JsonCreator methods but it requires to use #JsonProperty for specifying which property you are initializing.
#JsonCreator
public static StateOfComm factory(#JsonProperty("id") String id) {
return StateOfComm.valueOf(id);
}
#JsonCreator
public static StateOfComm factory(#JsonProperty("value") CustomType value) {
return StateOfComm.valueOf(value.getId());
}
I have a non-static data which I need to use on conversion. How can I transfer this data into my adapter class? Probably can I use a XmlAdapter in JAXB RI without an empty constructor (and without annotation of course)?
public class VariableAdapter extends XmlAdapter<String, Variable> {
private Map<String, Variable> varMap;
public VariableAdapter(Map<String, Variable> aVarMap) {
varMap = aVarMap;
}
public Variable unmarshal(String aVarName) {
return varMap.get(aVarName);
}
public String marshal(Variable v) {
return v.getName();
}
}
Here is my class, which I need to convert from/into XML
public class Variable {
private String name;
private Object value;
public Value(String aName, Object aValue) {
name = aName;
value = aValue;
}
public String getName() {return name;}
public Object getValue() {return value;}
public void setValue(Object aValue) {value = aValue;}
}
All Variable objects are initialized before XML processing and must be serialized per its name. Variable after unmarshalling can get another value (if its value was changed between serialization/deserialization).
By default JAXB will create a new instance of the XmlAdapter. You can call the setAdapter method on Marshaller/Unmarshaller to specify a stateful one.
For More Information
http://blog.bdoughan.com/2011/09/mixing-nesting-and-references-with.html
I have an Item class. There's an itemType field inside of that class which is of type ItemType.
roughly, something like this.
class Item
{
int id;
ItemType itemType;
}
class ItemType
{
String name;
int somethingElse;
}
When I am serializing an object of type Item using Jackson ObjectMapper, it serializes the object ItemType as a sub-object. Which is expected, but not what I want.
{
"id": 4,
"itemType": {
"name": "Coupon",
"somethingElse": 1
}
}
What I would like to do is to show the itemType's name field instead when serialized.
Something like below.
{
"id": 4,
"itemType": "Coupon"
}
Is there anyway to instruct Jackson to do so?
Check out #JsonValue annotation.
EDIT: like this:
class ItemType
{
#JsonValue
public String name;
public int somethingElse;
}
You need to create and use a custom serializer.
public class ItemTypeSerializer extends JsonSerializer<ItemType>
{
#Override
public void serialize(ItemType value, JsonGenerator jgen,
SerializerProvider provider)
throws IOException, JsonProcessingException
{
jgen.writeString(value.name);
}
}
#JsonSerialize(using = ItemTypeSerializer.class)
class ItemType
{
String name;
int somethingElse;
}
As OP only wants to serialize one field, you could also use the #JsonIdentityInfo and #JsonIdentityReference annotations:
class Item {
int id;
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="name")
#JsonIdentityReference(alwaysAsId=true)
ItemType itemType;
}
For more info, see How to serialize only the ID of a child with Jackson.
Perhaps a quick workaround is to add an extra getter on Item to return ItemType.name, and mark ItemType getter with #JsonIgnore?
To return simple string, you can use default ToStringSerializer without define any extra classes. But you have to define toString() method return this value only.
#JsonSerialize(using = ToStringSerializer.class)
class ItemType
{
String name;
int somethingElse;
public String toString(){ return this.name;}
}