Custom mapper for mapping entity to rf proxy

62 views
Skip to first unread message

-sowdri-

unread,
Apr 20, 2012, 4:56:02 AM4/20/12
to google-we...@googlegroups.com
Hi,

RF automatically maps entities to RF Proxy. Is there a way in which we could pass a custom mapper?

Thanks, 

Thomas Broyer

unread,
Apr 20, 2012, 5:16:30 AM4/20/12
to google-we...@googlegroups.com

On Friday, April 20, 2012 10:56:02 AM UTC+2, -sowdri- wrote:
RF automatically maps entities to RF Proxy. Is there a way in which we could pass a custom mapper?

Almost everything in RequestFactory on the server side is done by a ServiceLayerDecorator; in this case resolveClientType. The default implementation uses the DeobfuscatorBuilder that's being generated by the ValidationTool (or equivalent annotation processor during compilation); but you can very-well make your own DeobfuscatorBuilder instead of relying on automatic generation (we do just that in our project, because we have properties on our proxies with no direct equivalent on our domain objects, the property is "implemented" by a custom ServiceLayerDecorator overriding the getProperty and setProperty methods).

Thomas Broyer

unread,
Apr 20, 2012, 5:31:05 AM4/20/12
to google-we...@googlegroups.com
Oops, actually, our real need for the custom-generated DeobfuscatorBuilder is because we have methods on our RequestContext that do not match service methods directly (we have some kind of "translation" of the parameter and return types; this is really hackish so I won't go into the details here, but we have that translation of types taking place, so we have to mark our methods with @SkipInterfaceValidation, and instead of overriding resolveDomainMethod in a ServiceLayerDecorator, we generate the mapping in the DeobfuscatorBuilder).
For properties on proxies, you can actually simply mark them with @SkipInterfaceValidation and "implement" them in a ServiceLayerDecorator, you don't need to tweak the DeobfuscatorBuilder as there's nothing to be "resolved" here.

-sowdri-

unread,
Apr 20, 2012, 5:44:02 AM4/20/12
to google-we...@googlegroups.com
>> For properties on proxies, you can actually simply mark them with @SkipInterfaceValidation 

Actually the proxy interface is compatible with the entity. Just that for one of the values, rather then using the value in the entity, i want to make a db call to populate the value. That 's why I'm looking for the actual place where this mapping is taking place, such that I can override the default behavior only for this one entity. 

>> "implement" them in a ServiceLayerDecorator.

Can you provide some more details regarding this?

Thanks for the clarification,

-sowdri-

unread,
Apr 20, 2012, 5:45:48 AM4/20/12
to google-we...@googlegroups.com
As you were doing in your project, this kind of supplying a custom mapper for proxy to entity mapping could be a common requirement. 

Any thoughts on whether it would be appropriate to file a bug requesting this feature in RF?

Thomas Broyer

unread,
Apr 20, 2012, 6:06:44 AM4/20/12
to google-we...@googlegroups.com


On Friday, April 20, 2012 11:44:02 AM UTC+2, -sowdri- wrote:
>> For properties on proxies, you can actually simply mark them with @SkipInterfaceValidation 

Actually the proxy interface is compatible with the entity. Just that for one of the values, rather then using the value in the entity, i want to make a db call to populate the value. That 's why I'm looking for the actual place where this mapping is taking place, such that I can override the default behavior only for this one entity. 

>> "implement" them in a ServiceLayerDecorator.

Can you provide some more details regarding this?

class LoadFromDbServiceLayer extends ServiceLayerDecorator {
   @Override
   public Object getProperty(Object domainObject, String propertyName) {
      if (domainObject instanceof SomeDomainObject && "someProperty".equals(propertyName)) {
         // make db call and return the value
      }
      return super.getProperty(domainObject, propertyName);
   }
}

Note that this depends on the domain type, you don't know the proxy type here (as, technically, the same domain object instance can be exposed as 2 distinct proxy instances).

If you want to depend on the proxy type instead, make it "incompatible" with the domain type (change the property name on the proxy and mark it with @SkipInterfaceValidation), so that you can check for that name in the ServiceLayerDecorator.

Thomas Broyer

unread,
Apr 20, 2012, 6:23:22 AM4/20/12
to google-we...@googlegroups.com


On Friday, April 20, 2012 11:45:48 AM UTC+2, -sowdri- wrote:
As you were doing in your project, this kind of supplying a custom mapper for proxy to entity mapping could be a common requirement.

I sincerely doubt it.

We made very bad choices upfront that led us to this situation (in brief: we have very large entities with many embedded objects –equivalent to @Embedded in JPA/JDO– several levels deep, and we wanted to expose them as EntityProxies, so we have to craft fake IDs for the embedded objects –ID of the entity + property-path to the embedded– and use "wrapper" objects as domain objects to pair the embedded objects and their fake IDs, and this is why we need that "transaltion" to take place: our service methods take proxies on the client-side, and wrappers on the server-side; we validate things at build time –similar to the ValidationTool– and generate a DeofuscatorBuilder, instead of doing expensive computations at runtime to resolve the domain method)
This is a very singular situation.

We do many other things using ServiceLayerDecorators that are very easy: "implementing" fake properties, handling authorization on service methods, and doing dependency-injection on Locators and ServiceLocators (getting them out of our Guice Injector)
 
Any thoughts on whether it would be appropriate to file a bug requesting this feature in RF?

I don't know what kind of feature you're asking for, but it's likely to not actually be needed.
If you do think there's a missing feature though, let's discuss it! (here or on the GWT-Contributors group)

--sowdri--

unread,
Apr 20, 2012, 6:59:09 AM4/20/12
to google-we...@googlegroups.com
Regarding the LoadFromDbServiceLayer: 

This is exactly what I was looking for. Thanks.

Regarding pluggable mappers:

In our applications, for each entity the actual relationship with other object(s) is by encapsulating the instance of others (typical for ORM layer). But in our DTOs in most cases the Id/Business Key is sufficient instead of the whole object. 

In projects not using RF, (ie RPC) the service layer is using only DTOs and the delegate layer is working on entities. Here the entity to DTO conversion and vice-verse is being done using Dozer

When it comes to RF,
  • I should either make the service layer to work with DTOs and then create proxies. (double work) or
  • I should use something like 'LoadFromDbServiceLayer' for each such property. 

In short, the current impl of RF supports Proxies (which i believe to play the role to DTOs) which are only the mirror of the entities. It is just like a proxy layer that is same as entity layer.

Thanks,

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-web-toolkit/-/IZmqP40Rb2UJ.

To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.



--
-sowdri-

-sowdri-

unread,
Apr 20, 2012, 7:44:30 AM4/20/12
to google-we...@googlegroups.com
Regarding the LoadFromDbServiceLayer: 

This is exactly what I was looking for. Thanks.

Regarding pluggable mappers:

In our applications, for each entity the actual relationship with other object(s) is by encapsulating the instance of others (typical for ORM layer). But in our DTOs in most cases the Id/Business Key is sufficient instead of the whole object. 

In projects not using RF, (ie RPC) the service layer is using only DTOs and the delegate layer is working on entities. Here the entity to DTO conversion and vice-verse is being done using Dozer

When it comes to RF,
  • I should either make the service layer to work with DTOs and then create proxies. (double work) or
  • I should use something like 'LoadFromDbServiceLayer' for each such property. 

In short, the current impl of RF supports Proxies (which i believe to play the role to DTOs) which are only the mirror of the entities. It is just like a proxy layer that is same as entity layer.

Thanks,

Thomas Broyer

unread,
Apr 20, 2012, 8:39:17 AM4/20/12
to google-we...@googlegroups.com


On Friday, April 20, 2012 12:59:09 PM UTC+2, -sowdri- wrote:
Regarding the LoadFromDbServiceLayer: 

This is exactly what I was looking for. Thanks.

Regarding pluggable mappers:

In our applications, for each entity the actual relationship with other object(s) is by encapsulating the instance of others (typical for ORM layer). But in our DTOs in most cases the Id/Business Key is sufficient instead of the whole object.


FYI, we're doing the exact opposite: we do not use "object references" in our model but just store IDs, but we're exposing a property of an EntityProxy type on the client. We simply adopted a naming convention and an annotation: such fields are named fooId in the domain model, and exposed as a property foo on the proxy, and the field is annotated with @References(OtherEntity.class). In JPA/JDO/whataver, you'd typically have your field of type OtherEntity and let your ORM do the joins or lazy-loading or whatever.
With this rule, our "LazyLoadServiceLayer" looks for a field named propertyName + "Id" and annotated with a @References annotation; if that's the case, it then uses the value of the annotation and the value of the field to load the other entity and return it. And we cache the result of the field-lookup so we don't have to do it everytime (we particularly save the fact that there's no such field!).

In your case, you'd probably simply get the property's value from the super implementation and then look for its type; and if it's an entity then you'd return its ID instead.

See, it's really easy, no need for an additional "pluggable mapper".
Reply all
Reply to author
Forward
0 new messages