【问题标题】:@IntDef Android support annontation with Jackson deserializing@IntDef Android 支持带有 Jackson 反序列化的注释
【发布时间】:2015-06-30 09:08:43
【问题描述】:

将 JacksonAnnotations 与 Android 支持注释一起使用。我的 POJO 是:

@JsonIgnoreProperties(ignoreUnknown = true)
public class Schedule {
    public static final int SUNDAY = 0;
    public static final int MONDAY = 1;
    public static final int TUESDAY = 2;
    public static final int WEDNESDAY = 3;
    public static final int THURSDAY = 4;
    public static final int FRIDAY = 5;
    public static final int SATURDAY = 6;

    private Integer weekday;

    public Schedule() {
    }

    @Weekday
    public Integer getWeekday() {
        return weekday;
    }

    public void setWeekday(@Weekday Integer weekday) {
        this.weekday = weekday;
    }

    @Retention(RetentionPolicy.RUNTIME)
    @IntDef({SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY})
    public @interface Weekday {}
}

从支持我得到对象:

{"schedule":{"weekday":"MONDAY"}}

我想要的是将 Weekday 映射到常量中定义的整数值。有什么办法可以做到这一点?

更新:主要目的是优化(你应该严格避免在Android上使用枚举,就像here所说的那样)。

【问题讨论】:

  • 编写一个自定义的 json 反序列化器,并在提供的字符串和所需的 int 值之间进行更改。
  • 我当然知道自定义反序列化器和@JsonCreator。只是在寻找更“优雅”的解决方案。
  • 为什么使用 Integer 而不是 int ?装箱使您的代码效率甚至低于枚举。

标签: android json jackson android-support-library


【解决方案1】:

由于您可以指望工作日不会失去控制,因此创建静态地图似乎是一个非常干净的解决方案。提供一个名为fromString@JsonCreator 工厂将与杰克逊一起工作,也将与play nicely with JAX-RS

public class Schedule {
    ...
    private static final ImmutableMap<String, Schedule> WEEKDAY_TO_INT_MAP =
            ImmutableMap.<String, Schedule>builder()
                .put("SUNDAY", withIntWeekday(0))
                .put("MONDAY", withIntWeekday(1))
                .put("TUESDAY", withIntWeekday(2))
                .put("WEDNESDAY", withIntWeekday(3))
                .put("THURSDAY", withIntWeekday(4))
                .put("FRIDAY", withIntWeekday(5))
                .put("SATURDAY", withIntWeekday(6))
                .build();

    public static Schedule withIntWeekday(int weekdayInt) {
        Schedule schedule = new Schedule();
        schedule.setWeekday(weekdayInt);
        return schedule;
    }

    @JsonCreator
    public static Schedule fromString(String weekday) {
        return WEEKDAY_TO_INT_MAP.get(weekday);
    }
    ...
}

【讨论】:

    【解决方案2】:

    也许我错过了什么,但为什么不做这样的事情:

    public class Schedule {
        public enum Weekday {
            SUNDAY(0),
            MONDAY(1),
            TUESDAY(2),
            WEDNESDAY(3),
            THURSDAY(4),
            FRIDAY(5),
            SATURDAY(6);
    
            private final Integer weekday;
    
            Weekday(Integer weekday) {
                this.weekday = weekday;
            }
    
            public Integer getWeekday() {
                return weekday;
            }
        }
    
        private Weekday weekday;
    
        public Integer getWeekday() {
            return weekday.getWeekday();
        }
    
        public void setWeekday(Weekday weekday) {
            this.weekday = weekday;
        }
    
    }
    

    【讨论】:

    • 我不是安卓开发者。所以我刚刚学到了一些新东西。谢谢。我正要建议Sam B 的解决方案,在我写它的时候,我看到枚举可以做得更好。如果禁止使用 android 枚举 - 使用 Sam 的解决方案。或者它的缩写有ImmutableMap&lt;String, Int&gt;而不是时间表。
    • 你认为它会比使用枚举更有效吗?
    • 说实话,我不知道。我不知道android中的效率问题。我只是一名 Java 开发人员 :-) 我知道在纯 Java 中 - 枚举被认为是一种优化。参见例如 EnumMap vs Map。
    【解决方案3】:

    如果后端将"MONDAY" 作为字符串返回,那么您可能不应该使用@IntDef,因为您必须管理将"MONDAY" 转换为整数值。

    我会尝试使用@StringDef 注释,这样您就不必担心后端和客户端应用程序之间的任何类型的转换。唯一的问题是您需要从后端获得可靠的响应并提前同意命名约定。

    如果您将类型从 @IntDef 更改为 @StringDef,它将如下所示:

    @JsonIgnoreProperties(ignoreUnknown = true)
    public class Schedule {
        public static final String SUNDAY = "SUNDAY";
        public static final String MONDAY = "MONDAY";
        public static final String TUESDAY = "TUESDAY";
        public static final String WEDNESDAY = "WEDNESDAY";
        public static final String THURSDAY = "THURSDAY";
        public static final String FRIDAY = "FRIDAY";
        public static final String SATURDAY = "SATURDAY";
    
        private String weekday;
    
        public Schedule() {
        }
    
        @Weekday
        public String getWeekday() {
            return weekday;
        }
    
        public void setWeekday(@Weekday String weekday) {
            this.weekday = weekday;
        }
    
        @Retention(RetentionPolicy.RUNTIME)
        @StringDef({SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY})
        public @interface Weekday {}
    }
    

    【讨论】:

    • 我仍然需要枚举(工作日数)中的 .ordinal() 值,所以这对我来说不是解决方案。
    • 如果您需要 .ordinal() 值,那么使用枚举是最有意义的。尽管枚举比@IntDef 更昂贵,但它比创建另一个数据结构更便宜,这将是你唯一的选择。看起来 UriShalit 的答案最好。
    • 我不这么认为。带有 ifs 比较值字符串和分配和整数的事件设置器会更轻。 UriShalit 的答案是我现在想要优化的。
    • 你是对的,它会更轻,但它似乎并不简单。我认为您可能已经有了最简单的解决方案,除非您需要您的应用程序非常高效,否则您可能希望坚持使用它的方式。
    【解决方案4】:

    优雅的解决方案是使用枚举。

    有效的解决方案是编写一个自定义序列化程序,使用 switch 语句将工作日字符串映射到 int,反之亦然。

    您还可以使用序列化程序中的反射访问 StringDef 注释中的值,但这会更慢且可读性更低。

    【讨论】:

      猜你喜欢
      • 2019-08-10
      • 2018-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-26
      • 1970-01-01
      • 1970-01-01
      • 2014-11-11
      相关资源
      最近更新 更多