In [5]: list(set(temp1) - set(temp2))
Out[5]: ['Four', 'Three']
Остерегайтесь
In [5]: set([1, 2]) - set([2, 3])
Out[5]: set([1])
, где вы можете ожидать / хотите, чтобы он был равен set([1, 3])
. Если вы хотите, чтобы в качестве ответа вы set([1, 3])
, вам нужно использовать set([1, 2]).symmetric_difference(set([2, 3]))
.
Решение сериализатора / десериализатора, указанное xbakesx, является превосходным, если вы хотите полностью разделить класс enor enum из его представления JSON.
Альтернативно, если вы предпочитаете автономное решение, реализация основанные на @JsonCreator и @JsonValue, были бы более удобными.
Таким образом, используя пример Стэнли, это полное автономное решение (Java 6, Jackson 1.9):
public enum DeviceScheduleFormat {
Weekday,
EvenOdd,
Interval;
private static Map<String, DeviceScheduleFormat> namesMap = new HashMap<String, DeviceScheduleFormat>(3);
static {
namesMap.put("weekday", Weekday);
namesMap.put("even-odd", EvenOdd);
namesMap.put("interval", Interval);
}
@JsonCreator
public static DeviceScheduleFormat forValue(String value) {
return namesMap.get(StringUtils.lowerCase(value));
}
@JsonValue
public String toValue() {
for (Entry<String, DeviceScheduleFormat> entry : namesMap.entrySet()) {
if (entry.getValue() == this)
return entry.getKey();
}
return null; // or fail
}
}
В контексте перечисления, используя @JsonValue
сейчас (начиная с версии 2.0), работает для сериализации и десериализации.
Согласно аннотации джоксона javadoc для @JsonValue
:
ПРИМЕЧАНИЕ. При использовании для перечислений Java одна дополнительная функция - это то, что значение, возвращаемое аннотированным методом, также считается значением десериализации, а не только JSON Строка для сериализации как. Это возможно, так как множество значений Enum является постоянным, и можно определить отображение, но не может быть сделано вообще для типов POJO; как таковой, это не используется для десериализации POJO.
Итак, с enumated
Event
, аннотированным так же, как описано выше (для сериализации и десериализации) с jackson 2.0 +.
Вот еще один пример, который использует строковые значения вместо карты.
public enum Operator {
EQUAL(new String[]{"=","==","==="}),
NOT_EQUAL(new String[]{"!=","<>"}),
LESS_THAN(new String[]{"<"}),
LESS_THAN_EQUAL(new String[]{"<="}),
GREATER_THAN(new String[]{">"}),
GREATER_THAN_EQUAL(new String[]{">="}),
EXISTS(new String[]{"not null", "exists"}),
NOT_EXISTS(new String[]{"is null", "not exists"}),
MATCH(new String[]{"match"});
private String[] value;
Operator(String[] value) {
this.value = value;
}
@JsonValue
public String toStringOperator(){
return value[0];
}
@JsonCreator
public static Operator fromStringOperator(String stringOperator) {
if(stringOperator != null) {
for(Operator operator : Operator.values()) {
for(String operatorString : operator.value) {
if (stringOperator.equalsIgnoreCase(operatorString)) {
return operator;
}
}
}
}
return null;
}
}
Я нашел очень приятное и сжатое решение, особенно полезное, когда вы не можете модифицировать классы enum, как это было в моем случае. Затем вы должны предоставить настраиваемый ObjectMapper с включенной определенной функцией. Эти функции доступны с Jackson 1.6. Таким образом, вам нужно всего лишь написать метод toString()
в вашем перечислении.
public class CustomObjectMapper extends ObjectMapper {
@PostConstruct
public void customConfiguration() {
// Uses Enum.toString() for serialization of an Enum
this.enable(WRITE_ENUMS_USING_TO_STRING);
// Uses Enum.toString() for deserialization of an Enum
this.enable(READ_ENUMS_USING_TO_STRING);
}
}
Доступно больше функций, связанных с перечислением, см. Здесь:
https: // github.com/FasterXML/jackson-databind/wiki/Serialization-Features https://github.com/FasterXML/jackson-databind/wiki/Deserialization-Features
Вы можете настроить десериализацию для любого атрибута.
Объявить класс десериализации, используя аннотацию JsonDeserialize (import com.fasterxml.jackson.databind.annotation.JsonDeserialize
) для атрибута, который будет обработан. Если это Enum:
@JsonDeserialize(using = MyEnumDeserialize.class)
private MyEnum myEnum;
Таким образом, ваш класс будет использоваться для десериализации атрибута. Это полный пример:
public class MyEnumDeserialize extends JsonDeserializer<MyEnum> {
@Override
public MyEnum deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
MyEnum type = null;
try{
if(node.get("attr") != null){
type = MyEnum.get(Long.parseLong(node.get("attr").asText()));
if (type != null) {
return type;
}
}
}catch(Exception e){
type = null;
}
return type;
}
}
Существуют различные подходы, которые вы можете предпринять для выполнения десериализации объекта JSON для перечисления. Мой любимый стиль - создать внутренний класс:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.NotEmpty;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.fasterxml.jackson.annotation.JsonFormat.Shape.OBJECT;
@JsonFormat(shape = OBJECT)
public enum FinancialAccountSubAccountType {
MAIN("Main"),
MAIN_DISCOUNT("Main Discount");
private final static Map<String, FinancialAccountSubAccountType> ENUM_NAME_MAP;
static {
ENUM_NAME_MAP = Arrays.stream(FinancialAccountSubAccountType.values())
.collect(Collectors.toMap(
Enum::name,
Function.identity()));
}
private final String displayName;
FinancialAccountSubAccountType(String displayName) {
this.displayName = displayName;
}
@JsonCreator
public static FinancialAccountSubAccountType fromJson(Request request) {
return ENUM_NAME_MAP.get(request.getCode());
}
@JsonProperty("name")
public String getDisplayName() {
return displayName;
}
private static class Request {
@NotEmpty(message = "Financial account sub-account type code is required")
private final String code;
private final String displayName;
@JsonCreator
private Request(@JsonProperty("code") String code,
@JsonProperty("name") String displayName) {
this.code = code;
this.displayName = displayName;
}
public String getCode() {
return code;
}
@JsonProperty("name")
public String getDisplayName() {
return displayName;
}
}
}
Вы должны создать статический заводский метод, который принимает один аргумент и аннотирует его с помощью @JsonCreator
(доступно с Jackson 1.2)
@JsonCreator
public static Event forValue(String value) { ... }
Подробнее о аннотации JsonCreator здесь .
Обратите внимание, что с это commit в июне 2015 года (Jackson 2.6.2 и выше) теперь вы можете просто написать:
public enum Event {
@JsonProperty("forgot password")
FORGOT_PASSWORD;
}
Фактический ответ:
Дессериализатор по умолчанию для перечислений использует .name()
для десериализации, поэтому он не использует @JsonValue
. Так, как отметил @OldCurmudgeon, вам нужно пройти в {"event": "FORGOT_PASSWORD"}
, чтобы соответствовать значению .name()
.
Другой вариант (если вы хотите, чтобы значения записи и чтения json были одинаковыми) ...
Дополнительная информация:
Существует еще один способ управления процессом сериализации и десериализации с помощью Jackson. Вы можете указать эти аннотации для использования своего собственного сериализатора и десериализатора:
@JsonSerialize(using = MySerializer.class)
@JsonDeserialize(using = MyDeserializer.class)
public final class MyClass {
...
}
Затем вам нужно написать MySerializer
и MyDeserializer
, которые выглядят следующим образом:
MySerializer
public final class MySerializer extends JsonSerializer<MyClass>
{
@Override
public void serialize(final MyClass yourClassHere, final JsonGenerator gen, final SerializerProvider serializer) throws IOException, JsonProcessingException
{
// here you'd write data to the stream with gen.write...() methods
}
}
MyDeserializer
public final class MyDeserializer extends org.codehaus.jackson.map.JsonDeserializer<MyClass>
{
@Override
public MyClass deserialize(final JsonParser parser, final DeserializationContext context) throws IOException, JsonProcessingException
{
// then you'd do something like parser.getInt() or whatever to pull data off the parser
return null;
}
}
Последнее немного, особенно для этого с перечислением JsonEnum
, которое сериализуется с помощью метода getYourValue()
, ваш сериализатор и десериализатор могут выглядеть так: это:
public void serialize(final JsonEnum enumValue, final JsonGenerator gen, final SerializerProvider serializer) throws IOException, JsonProcessingException
{
gen.writeString(enumValue.getYourValue());
}
public JsonEnum deserialize(final JsonParser parser, final DeserializationContext context) throws IOException, JsonProcessingException
{
final String jsonValue = parser.getText();
for (final JsonEnum enumValue : JsonEnum.values())
{
if (enumValue.getYourValue().equals(jsonValue))
{
return enumValue;
}
}
return null;
}