Skip to content

Instantly share code, notes, and snippets.

@fuxingloh
Created June 25, 2019 19:13
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save fuxingloh/386565885891b120aae4a5d3fd74a20c to your computer and use it in GitHub Desktop.
Save fuxingloh/386565885891b120aae4a5d3fd74a20c to your computer and use it in GitHub Desktop.
Java Enum, @ValidEnum with Constraint that supports JsonIgnoreProperties if not registered. Basically: how to handle unknown enum values in swift & java.

So, null & unknown value handling for enum has always been an issue for me when converting from JSON to Java.

I saw this implementation in Amazon Java SDK packages. Really liked it so I expanded on it to support JSON using the Jackson packages. I have also created @ValidEnum constraints to support using Hibernate Validator library.

Features

  • IntelliJ Live Template
  • Hibernate Validator
  • JSON, Jackson support
  • Null, Unknown value handling.
  • A Swift implementation
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* Created by: Fuxing
*/
public class EnumValidator implements ConstraintValidator<ValidEnum, Enum> {
@Override
public boolean isValid(Enum value, ConstraintValidatorContext context) {
if (value == null) return false;
return !value.toString().equals("null");
}
}
$END$
UNKNOWN_TO_SDK_VERSION(null);
private final String value;
$CLASS_NAME$(String value) {
this.value = value;
}
@Override
@com.fasterxml.jackson.annotation.JsonValue
public String toString() {
return String.valueOf(value);
}
/**
* Use this in place of valueOf to convert the raw string returned by the service into the enum value.
*
* @param value real value
* @return $CLASS_NAME$ corresponding to the value
*/
@com.fasterxml.jackson.annotation.JsonCreator
public static $CLASS_NAME$ fromValue(String value) {
if (value == null) {
return null;
}
return java.util.stream.Stream.of($CLASS_NAME$.values()).filter(e -> e.toString().equals(value)).findFirst()
.orElse(UNKNOWN_TO_SDK_VERSION);
}
public static java.util.Set<$CLASS_NAME$> knownValues() {
return java.util.stream.Stream.of(values()).filter(v -> v != UNKNOWN_TO_SDK_VERSION).collect(java.util.stream.Collectors.toSet());
}
/**
* Created by: Fuxing
*/
public enum Status {
DRAFT("DRAFT"),
DELETED("DELETED"),
PUBLISHED("PUBLISHED"),
UNKNOWN_TO_SDK_VERSION(null);
private final String value;
Status(String value) {
this.value = value;
}
@Override
@JsonValue
public String toString() {
return String.valueOf(value);
}
/**
* Use this in place of valueOf to convert the raw string returned by the service into the enum value.
*
* @param value real value
* @return Status corresponding to the value
*/
@JsonCreator
public static Status fromValue(String value) {
if (value == null) {
return null;
}
return Stream.of(Status.values()).filter(e -> e.toString().equals(value)).findFirst()
.orElse(UNKNOWN_TO_SDK_VERSION);
}
public static Set<Status> knownValues() {
return Stream.of(values()).filter(v -> v != UNKNOWN_TO_SDK_VERSION).collect(Collectors.toSet());
}
}
enum Status: String, Codable {
case DRAFT
case DELETED
case PUBLISHED
case UNKNOWN_TO_SDK_VERSION
init(from decoder: Decoder) throws {
switch try decoder.singleValueContainer().decode(String.self) {
case "DRAFT": self = .DRAFT
case "DELETED": self = .DELETED
case "PUBLISHED": self = .PUBLISHED
default: self = .UNKNOWN_TO_SDK_VERSION
}
}
}
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.lang.annotation.ElementType.*;
/**
* Validate enum that are structured with nullable string.
* Will fail = null, or "null"
*
* @see Example for example of how it works.
* <p>
* Created by: Fuxing
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Constraint(validatedBy = EnumValidator.class)
public @interface ValidEnum {
String message() default "enum not valid";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
/**
* This is an example of an enum that works with ValidEnum.
*/
enum Example {
EXAMPLE("EXAMPLE"),
// If any enum is this value, it will fail validation
UNKNOWN_TO_SDK_VERSION(null);
private final String value;
Example(String value) {
this.value = value;
}
@Override
@JsonValue
public String toString() {
return String.valueOf(value);
}
/**
* Use this in place of valueOf to convert the raw string returned by the service into the enum value.
*
* @param value real value
* @return Example corresponding to the value
*/
@JsonCreator
public static Example fromValue(String value) {
if (value == null) {
return null;
}
return Stream.of(Example.values()).filter(e -> e.toString().equals(value)).findFirst()
.orElse(UNKNOWN_TO_SDK_VERSION);
}
public static Set<Example> knownValues() {
return Stream.of(values()).filter(v -> v != UNKNOWN_TO_SDK_VERSION).collect(Collectors.toSet());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment