【问题标题】:Deserializing from JSON using foreign key使用外键从 JSON 反序列化
【发布时间】:2017-10-09 16:23:23
【问题描述】:

我有一个多对一的关系:A *1 B,我想从具有 B 的 JSON 反序列化 A > 的主键(B 存在于具有该主键的数据库中):

{
    "b": 1
}

我尝试了以下方法:

@Entity
@Table(name = "table_a")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class A implements Serializable {

    @JsonIgnore
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name = "b", unique = true, nullable = false)
    private B b;
}

@Entity
@Table(name = "table_b")
public class B implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @OneToMany(mappedBy = "b")
    private List<A> a = new ArrayList<>();
}

但是对象 A 是用b = null 创建的。如何使用从 db 正确实例化的 b 属性反序列化 A

注意:我使用的是 Jackson 2.6.1 版。

【问题讨论】:

  • 您想从哪里获取 b 信息?查看 db 并创建自定义对象或仅使用 id 字段创建空的?

标签: java json jpa serialization jackson


【解决方案1】:

您有多种选择,这里是similar question

  1. @JsonCreatorB 类中的工厂 (More info)

  2. 自定义反序列化器

  3. 自定义ObjectIdResolver@JsonIdentityInfo 喜欢

    private class MyObjectIdResolver implements ObjectIdResolver {
        private Map<ObjectIdGenerator.IdKey,Object> _items  = new HashMap<>();
    
        @Override
        public void bindItem(ObjectIdGenerator.IdKey id, Object pojo) {
            if (!_items.containsKey(id)) _items.put(id, pojo); 
        }
    
        @Override
        public Object resolveId(ObjectIdGenerator.IdKey id) {
            Object object = _items.get(id);
            return object == null ? getById(id) : object;
        }
    
        protected Object getById(ObjectIdGenerator.IdKey id){
            Object object = null;
            try {
                //can resolve object from db here
                //objectRepository.getById((Integer)idKey.key, idKey.scope)
                object = id.scope.getConstructor().newInstance();
                id.scope.getMethod("setId", int.class).invoke(object, id.key);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return object;
        }
    
        @Override
        public ObjectIdResolver newForDeserialization(Object context) {
            return new MyObjectIdResolver();
        }
    
        @Override
        public boolean canUseFor(ObjectIdResolver resolverType) {
            return resolverType.getClass() == getClass();
        }
    }
    

    并像这样使用它:

    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
            resolver = MyObjectIdResolver.class, 
            property = "id", scope = B.class)
    public class B  {
       // ...
    }
    

这里是与您的案例相关的gist demo 更广泛的github project 以及一些序列化想法

【讨论】:

  • 嗨@varren,感谢您非常有趣的回答。我有一个问题:如何将对象存储库传递给ObjectIdResolver
  • 有很多选项需要考虑。 1)在创建 ObjectMapper 时将其注入 ObjectIdResolver 而不是注释like this 2)对您的存储库/服务/某个存储库工厂使用一些静态引用 3)可能只是自动装配它like here 更多信息here
  • @y.luis ppl 说你可以使用类似于stackoverflow.com/a/21562939/1032167SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);,实际上我从来没有缺乏过它。或许可以试试gist.github.com/varren/…
猜你喜欢
  • 2012-11-11
  • 2019-05-06
  • 2012-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多