2 Replies Latest reply: Jan 17, 2013 10:38 AM by Thomas Frühbeck RSS

Problem marshalling entities

Gilberto Pacheco Newbie

I start explaining my scenario and finish with a question related to it.

 

I´m using errai with Glassfish and EclipseLink. All of my RPCs work fine with beans marked as Portable. But when I try to use JPA entities I get this error:

 

SEVERE: org.jboss.errai.marshalling.client.api.exceptions.InvalidMappingException: portable entity net.ramptors.compro.client.modelo.Categoria contains a field (_persistence_fetchGroup) that is not known to the marshaller: org.eclipse.persistence.queries.FetchGroup

          at org.jboss.errai.marshalling.rebind.api.impl.defaultjava.DefaultJavaDefinitionMapper.map(DefaultJavaDefinitionMapper.java:226)

          at org.jboss.errai.marshalling.rebind.DefinitionsFactoryImpl.loadCustomMappings(DefinitionsFactoryImpl.java:289)

  ... (Stack trace continues)

 

That problem is solved using the following mapping:

 

@CustomMapping

public class CategoriaMapping extends MappingDefinition {

  public CategoriaMapping() {

    super(Categoria.class);

    final SimpleConstructorMapping cnsMapping = new SimpleConstructorMapping();

    cnsMapping.mapParmToIndex("id", 0, Integer.class);

    cnsMapping.mapParmToIndex("nombre", 2, String.class);

    setInstantiationMapping(cnsMapping);

    addMemberMapping(new ReadMapping("id", Integer.class, "getId"));

    addMemberMapping(new ReadMapping("nombre", String.class, "getNombre"));

  }

}

 

I need to work this way because Eclipselink adds fields to the compiled class. If I use regular GWT-RPC my class works out of the box with no workarround because GWT knows that ORM entities are usually modified.

 

QUESTION

Is there a way to configure Errai so I don't have to create mappings for ORM entities? If there is no way, I think this case should be considered in Errai-RPC because its á very common situation in enterprise applications.

  • 1. Re: Problem marshalling entities
    Mike Brock Master

    This is a common problem with JPA entities. JPA containers proxy JPA entities to handle things like lazy loading. In Hibernate there is a utility that can be used to unproxy entities. I'm not sure about EclipseLink.

     

    The "proper" way to do it is to use DTOs. And that's generally how most people work around this problem.

     

    If you're trying to avoid writing a DTO for every JPA entity, you could consider something more along these lines:

     

     

    @Entity
    @Portable
    public class User {
        @Id @GeneratedValue
        private int id;
    
        private String name;
    
        public long getId() {
          return id;
        }
    
        public void setId(int id) {
          this.id = id;
        }
    
        public String getName() {
          return this.name;
        }
    
        public void setName(String name) {
          this.name = name;
        }
    
        /** create an unproxied version **/
        @Transient
        public User snapshot() {
          final User user = new User();
          user.id = id;
          user.name = name;
    
          return user;
        }
    }
    

     

    Then when you're sending data to the client, you would call snapshot(), which would produce an unproxied version of the entity. This is less work than a DTO. But there's disadvantages in the sense that with a DTO you have a layer of abstraction where you can limit what goes over the wire to just what you need, and you're also more likely to forget to update the snapshot() method, than to update a DTO when the model changes.

     

    But those are really my only two suggestions. We used to have a feature that would unproxy hibernate entities built-in to Errai, but it's since been removed as it is non-portable.

     

    To be honest, it would be nice if when they generated the proxies, the introduced fields were transient. Because then, at least, Errai would ignore them automatically.

  • 2. Re: Problem marshalling entities
    Thomas Frühbeck Newbie

    I am surprised to find Errai fall short in handling object instantiation and property mapping in a state-of-the-art way, even more as most frameworks do a decent job in bridging the gap between Web and persistence.

     

    I am currently working on a non-DTO solution for Errai Marshalling.

    I want to solve two main issues:

         - server side entity instantiation _before_ demarshalling via ConstructorMapping

         - handling of entity references such that not the referenced object, but an abstraction is passed to the client

    It currently consists of an EntiyMappingDefinition, EntityMarshaller and a perhaps avoidable EntityWrapper, which is serializeable.

     

    During my investigations I was surprised to find, that Errai marshalling does not use/provide CDI?

    Is there a technical reason, why it is not possible to register a CDI enabled object/entity factory as ConstructorMapping or is this just due to a lack of time?

     

    One of the biggest problems with the current constructor handling is that there is no distinction between server and client side, and that it is required to be a method of the object, so no CDI-enabled factory possible. I try to work around it by remapping mapping definitions on server side after container startup, but it looks like a bad hack, and I'm not sure if it will be stable enough, because it is not integrated in Errai.

     

    Would you be interested in such a kinda seamless JPA-integration?

     

    Do you have any idea, how I can continue as erraiish as possible?