Wanting to get Enum Value instead of name in JSON - java

I've got the following enum:
public enum NotificationType {
Store("S"),
Employee("E"),
Department("D"),
All("A");
public String value;
NotificationType(String value) {
this.value = value;
}
#Override
public String toString() {
return this.value;
}
#JsonCreator
public static NotificationType fromValue(String value) {
for (NotificationType type : NotificationType.values()) {
if (type.value.equals(value)) {
return type;
}
}
throw new IllegalArgumentException();
}
}
I've created a converter so that when the enum is saved to the database, it persists the value (S, E, D or A) instead of the name. And I can POST json to the controller with the value and it binds to the object correctly.
However, when I render the JSON from a GET it is still displaying the name (Employee, Store, etc) and I would prefer that it still show the value.

Because your toString method returns the value you want to use to represent your enum, you can annotate it with #JsonValue to tell Jackson that the return value represents the value of the enum.

Related

Best validation method for a dynamic class in java (Micronaut)

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.

Saving Enum name instead of value in couchbase

I am working on spring data couchbase application.In oracle its saving the enum with name but in couchbase its value. I want to save enum name in couchbase instead of its value. But i dont want to change this below existing code.
Is there any way to do that?
And the enum is not a direct field in document. Its a key value in map of other attribute
public enum Foo {
Moon("Night"),
Star("Night"),
Sun("Day");
private String value;
Foo(String value) {
this.value = value;
}
public String getValue() {
return value;
}
#Override
public String toString() {
return this.value;
}
public class Universe{
Map<Foo, <List<List<Cone>>> bar;
}
Couchbase entity class is using
private List<Universe> universe;

Validate JSON field against enum

I am constructing my POJO directly from the received JSON using Jackson's ObjectMapper. For that purpose I annotate my fields (in this case fields are abstract methods because I'm using AutoValue to reduce boilerplate) with #JsonProperty annotations.
Now, some of the fields in my POJO are enums, where JSON obviously contains a regular string. I would like to somehow validate that those JSON fields do indeed submit to the given enum type before the object is constructed.
Here is the example.
#JsonProperty(value = "messageType")
public abstract Optional<MessageType> messageType();
This property is of type enum MessageType, and the corresponding JSON field is ie. "messageType": "A_1" which is a string.
Now, if the "messageType" is something like "blabla" I'd like the validation to fail.
Is there any way to validate that with annotations using Hibernate Validator?
#JsonProperty(value = "messageType")
public abstract Optional messageType();
Assumed you have, MessageType as enum with distinct values A_1, A_2...
Create a static utility method to serialize/deserialize for the enum values from the received/sent json values
public static <T extends Enum<T>> T getEnumFromJson(Class<T> enumClass, String value)
{
if(enumClass == null) throw new IllegalArgumentException("EnumClass value can't be null");
for(Enum<?> enumValue : enumClass.getEnumConstants()){
if(enumValue.toString().equalsIgnoreCase(value)){
return (T) enumValue;
}
}
//Validation message construct to give more meaningful details to end-user
StringBuilder erroMsg = new StringBuilder();
boolean bFirst = true;
for(Enum<?> enumValue : enumClass.getEnumConstants()) {
errorMessage.append(bFirst ? "": ", ").append(enumValue);
bFirst = false;
}
throw new IllegalArgumentException(value + " is invalid value, Supported value are "+ errorMessage);
}
//Enum as represented below
public enum MessageType {
A_1,
A_2,
A_3
#JsonCreator
public static MessageType fromValue(String value){
return getEnumFromJson(MessageType.class, value);
}
#JsonValue
public String toJson(){
return name().toLowerCase();
}
}

Serialize field bypassing getter

How to use field value instead of getter due serialization with Jackson?
class Entity {
public String value;
Entity(String v) {
value = v;
}
#JsonIgnore // This makes field ignored too.
public String getValue() {
return "foo";
}
}
So I want this code to return {"value":"bar"}, but it returns {"value":"foo"} without #JsonIgnore, and {} with it:
new ObjectMapper().writeValueAsString(entity);

java/jackson - #JsonValue/#JsonCreator and null

I have a Value class which holds a value:
public class Value {
protected final Object value;
#JsonValue
public Object getValue() {
return value;
}
#JsonCreator
public Value(final Object value) {
this.value = value;
}
}
This Value class is embedded as a field (amongst other fields) in a data class:
class Data {
protected final Value value;
#JsonProperty("value")
public Value getValue() {
return value;
}
...
#JsonCreator
public Data(#JsonProperty("value") final Value value, ...) {
this.value = value;
....
}
}
When the input JSON has null for the value field of a data object (see below for example), Data.value is null. I would like to have Data.value set to new Value(null). In other words, the data object must hold a non-null value object, which holds the null.
{
"value" : null,
...
}
What is the easiest way to achieve this? I could ofcourse alter the constructor of Data, but I am wondering if Jackson could resolve this automatically.
You can write a custom de-serializer and override the getNullValue() method according to your requirements e.g.
public final class InstantiateOnNullDeserializer
extends JsonNodeDeserializer
{
#Override
public JsonNode getNullValue()
{
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.convertValue(new Value(null), JsonNode.class);
return node;
}
}
and register it on the value field of your Data class
class Data {
#JsonDeserialize(using = InstantiateOnNullDeserializer.class)
protected final Value value;
#JsonProperty("value")
public Value getValue() {
return value;
}
#JsonCreator
public Data(Value value) {
this.value = value;
}
}
Note that you need to remove the #JsonProperty("value") to avoid argument type mismatch. By removing JsonProperty annotation you create a so-called "delegate creator",
Jackson will than first bind JSON into type of the argument, and then call a creator
I do not believe that this is possible without creating your own deserializer or modify the constructor (or #JsonCreator).
From a good old thread in the Jackson User Group:
#JsonProperty does not support transformations, since the data binding is based on incremental parsing and does not have access to full tree representation.
So, in order to avoid a custom deserializer I would do something along the lines of:
#JsonCreator
public Data(#JsonProperty("value") final String value) {
this.value = new Value(value);
}
Which is kind of the opposite of what you asked ;)

Categories

Resources