Kryonet desirialization issue with Hibernate Entities

226 views Asked by At

I hope that someone might have had this or a similar problem before and could help me :)

I have a KryoNet Server / Client architecture, where I am sending messages. One of these Messages contains an instance of a class "WorldEntity". This entity looks something like this:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class WorldEntity {

    @OneToMany
    private Collection<EntityComponent> components;
}

I am using spring + hibernate to save this entity to my postgresql database. This works all fine.

When I am now sending this entity over to the client, the kryonet serializer tries to load the components lazily, which it should not do, since there is no hibernate or database on the client. In fact, all data is already contained in the entity.

I read somewhere, that a custom Serialization Object could be created and added to the KryoNet client, to disable this hibernate loading:

Kryo kryoSerializer = new Kryo() {

    @Override
    public Serializer<?> getDefaultSerializer(final Class type) {
        if (AbstractPersistentCollection.class.isAssignableFrom(type)) {
            return new FieldSerializer(kryoSerializer, type);
        }
        return super.getDefaultSerializer(type);
    }
};

This, unfortunately, can not be used as a Serialization object in the constructor of the Kryo Client.

Any help will be greatly appreciated!

Kind regards Dustin

1

There are 1 answers

0
Christian Beikov On

I would suggest you start thinking about adding DTOs for this purpose to also avoid exposing too much information to your clients for security but also network performance concerns. I think this is a perfect use case for Blaze-Persistence Entity Views.

I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.

A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:

@EntityView(WorldEntity.class)
public interface WorldEntityDto {
    @IdMapping
    Long getId();
    String getName();
    Set<EntityComponentDto> getComponents();

    @EntityView(EntityComponent.class)
    interface EntityComponentDto {
        @IdMapping
        Long getId();
        String getName();
    }
}

Querying is a matter of applying the entity view to a query, the simplest being just a query by id.

WorldEntityDto a = entityViewManager.find(entityManager, WorldEntityDto.class, id);

The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

Page<WorldEntityDto> findAll(Pageable pageable);

The best part is, it will only fetch the state that is actually necessary!