1

I have a many to one relationship: A *<-->1 B and I want to deserialize A from a JSON having B's primary key (B exists in db with that primary key):

{
    "b": 1
}

I have tried the following:

@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;
}

and

@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<>();
}

but object A is created with b = null. How can I deserialize A with b property correctly instantiated from db?

Note: I am using Jackson version 2.6.1.

y.luis.rojo
  • 1,794
  • 4
  • 22
  • 41
  • where do you want to get the b info from? look in db and create custom object or just create empty been with id field? – varren Oct 09 '17 at 19:55

1 Answers1

2

You have several options and here is similar question :

  1. @JsonCreator factory in B class (More info)

  2. Custom deserializer

  3. Custom ObjectIdResolver for @JsonIdentityInfo like

    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();
        }
    }
    

    And use it like this:

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

Here is your case related gist demo more broad github project with some serialization thoughts

varren
  • 14,551
  • 2
  • 41
  • 72
  • Hi @varren, thanks for your very interesting answer. I have one question about it: how can I pass an object repository to the `ObjectIdResolver`? – y.luis.rojo Oct 10 '17 at 11:34
  • There are lots of options to consider. 1) Inject it in ObjectIdResolver on ObjectMapper creation and not in annotation [like this](https://gist.github.com/ftagsold/38a92cba5467fe74ae6b) 2) use some static reference to your repository/service/some repository factory 3) probably just autowire it [like here](https://github.com/terrestris/shogun2/blob/master/src/shogun2-core/src/main/java/de/terrestris/shogun2/converter/PersistentObjectIdResolver.java#L35-L41) more info [here](https://github.com/terrestris/shogun2/search?utf8=%E2%9C%93&q=PersistentObjectIdResolver&type=) – varren Oct 10 '17 at 14:30
  • @y.luis ppl say you can use `SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);` similar to https://stackoverflow.com/a/21562939/1032167 I actually never had much lack with it. Can probably try something like https://gist.github.com/varren/c84da2f357a1d86b24bf137f3144cc3a#file-myobjectidresolverautowired-java – varren Oct 10 '17 at 14:36