3

I'm working on a project using Hibernate and Jackson to serialize my objects. I think I understand how it is suposed to work but I can't manage to make it works.

If I understand well, as soon as a relation fetch mode is set to LAZY, if you want this relation, you have to initialize it.

Here is my class :

@Entity
@JsonIgnoreProperties(ignoreUnknown = true)
@Table(schema="MDDI_ADMIN", name = "MINIUSINE")
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class MiniUsine {

    @Id
    @Column(name="MINIUSINEID", nullable = false)
    private int miniUsineID;

    @Column(name = "NAME", length = 40, nullable = false)
    private String name;

    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name="FluxID")
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    private Set<Flux> fluxs = new HashSet<Flux>();

And all getters and setters.

I've also tried this JsonInclude.Include.NON_EMPTY as class annotation. Also tried the NON_NULL. However, jackson keeps sending me

com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: MiniUsine.fluxs, no session or session was closed (through reference chain: java.util.ArrayList[0]->MiniUsine["fluxs"])

I'm serializing it with : mapper.writeValueAsString(optMU);

Using Jackson 2.3.2

Thanks for help

xNeyte
  • 602
  • 4
  • 17

2 Answers2

4

I know this is an old question but I had the same problem.

You must add a new maven dependecy to support JSON serialization and deserialization of Hibernate. I used Hibernate5 so I added

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-hibernate5</artifactId>
    <version>2.9.2</version>
</dependency>

Now register the new module.

@Provider
public class JacksonHibernateProvider implements ContextResolver<ObjectMapper> {

    @Override
    public ObjectMapper getContext(final Class<?> type) {
        final ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new Hibernate5Module());
        return mapper;
    }
}
Karl Richter
  • 6,271
  • 17
  • 57
  • 120
Igochan
  • 51
  • 2
3

As far as I understand, the entity object that hibernate returns is a proxy which derives from your entity class. If you try to access getter methods for lazy fields outside of a transaction, you get LazyInitializationException. The point I want to make is setting fluxs to empty set doesn't help you at all.

private Set<Flux> fluxs = new HashSet<Flux>();

Hibernate overloads the getter and if you try to access it outside of a transaction(which jackson is doing to check if it is empty), you get the LazyInit error.

saby
  • 158
  • 1
  • 1
  • 7
  • But it is supposed to not access it when it is empty (when I don't initialize it) because of `@JsonInclude(JsonInclude.Include.NON_EMPTY)` I never access it by myself, only jackson wants to access it when serializing the object – xNeyte Jun 07 '16 at 12:24
  • @JsonInclude(JsonInclude.Include.NON_EMPTY) means include this field only if it's non-empty. But to check whether its empty, Jackson needs to call .isEmpty() on the collection? However that collection is not the empty hash_set that you have provided. It is provided by hibernate. And that call will happen outside a transaction resulting in the error. – saby Jun 07 '16 at 12:26
  • Since the fetchmode is LAZY, the collection isn't supposed to be loaded if I don't initialize it, so it should be empty when jackson check it :( – xNeyte Jun 07 '16 at 12:31
  • http://stackoverflow.com/questions/25340606/what-does-the-hibernate-proxy-object-contain read the accepted answer. I hope it clears your doubts about how hibernate works. – saby Jun 07 '16 at 12:33
  • Ok I guess I understand, Hibernate tries to generate the collection when Jackson checks if it is empty or no but since session is close, it crashes. Is there anyway to avoid it so ? :/ – xNeyte Jun 07 '16 at 12:41
  • You can initialize the relation by calling entity.getFluxs().size() – saby Jun 07 '16 at 12:42
  • Yea but I would like to not initialize it because in THIS case, I won't need this collection and initializing it causes a big performance loss (since Flux will have another relation to something which will have again another relation to something else etc..) – xNeyte Jun 07 '16 at 12:45
  • You can try using @JsonIgnore to ignore it completely. Or if you need it in some cases you have to initialise by calling entity.getFluxs().size(). – saby Jun 07 '16 at 12:45
  • Ok si there is no way to generate it sometimes and avoid its at other time to boost performances, thanks for all explanations! – xNeyte Jun 07 '16 at 12:52