Avoiding the use of CGLIB?

96 views
Skip to first unread message

Gili

unread,
Oct 24, 2008, 5:42:21 PM10/24/08
to google-guice
Hi,

Is it possible to tell Guice to avoid the use of CGLIB unless it's
absolutely necessary? I know Guice uses it to solve circular
dependencies but I use the Provider<Foo> approach instead. CGLIB
proxies sometimes break compatibility. For example, today I ran into
this issue:
http://n2.nabble.com/com.sun.jersey.impl.uri.UriBuilderImpl.path()-throws-an-unexpected-exception-td1373393.html#a1373584

Thanks,
Gili

limpb...@gmail.com

unread,
Oct 24, 2008, 7:45:08 PM10/24/08
to google-guice


On Oct 24, 2:42 pm, Gili <gili.tzab...@gmail.com> wrote:
> Is it possible to tell Guice to avoid the use of CGLIB unless it's
> absolutely necessary? I know Guice uses it to solve circular
> dependencies but I use the Provider<Foo> approach instead. CGLIB
> proxies sometimes break compatibility. For example, today I ran into

Are you using method interceptors? We can't do them without CGLIB.

James Carman

unread,
Oct 24, 2008, 8:36:58 PM10/24/08
to google...@googlegroups.com
Can Jersey search the class hierarchy for the @Path annotation?

Gili Tzabari

unread,
Oct 25, 2008, 1:47:41 AM10/25/08
to google...@googlegroups.com

I don't do anything fancy. I just have Guice inject my classes. The
only Guice-specific thing I have is @Inject annotated constructors.

Gili

Sam Berlin

unread,
Oct 25, 2008, 11:26:01 AM10/25/08
to google...@googlegroups.com
I also often see what looks like CGLIB things (FastClassByGuice) in
stack traces and do not have any interceptors (though do have a few
circular dependencies). (Though it isn't causing any problems... just
thought I'd point it out.)

Sam

Gili

unread,
Oct 27, 2008, 10:30:02 AM10/27/08
to google-guice
Hi James,

I ran this question by the author of Jersey and he said that doing so
would violate the JAX-RS specification:
http://n2.nabble.com/com.sun.jersey.impl.uri.UriBuilderImpl.path()-throws-an-unexpected-exception-td1373393.html#a1381422

I need to somehow tell Guice to not use CGLIB or to annotate the
subclass with the same annotations as the superclass.

Gili

On Oct 24, 8:36 pm, "James Carman" <jwcar...@gmail.com> wrote:
> Can Jersey search the class hierarchy for the @Path annotation?
>

Stuart McCulloch

unread,
Oct 27, 2008, 2:00:35 PM10/27/08
to google...@googlegroups.com
2008/10/27 Gili <gili.t...@gmail.com>

Hi James,

I ran this question by the author of Jersey and he said that doing so
would violate the JAX-RS specification:
http://n2.nabble.com/com.sun.jersey.impl.uri.UriBuilderImpl.path()-throws-an-unexpected-exception-td1373393.html#a1381422

I need to somehow tell Guice to not use CGLIB or to annotate the
subclass with the same annotations as the superclass.

looking at the codebase it appears Guice uses CGLIB's FastClass
to create instances of public types when doing constructor injection,
even if there's no circular dependency or interception going on, see:

  src/com/google/inject/DefaultConstructionProxyFactory.java

afaik using FastClass here is just for performance, so it's technically
possible to add some sort of switch to turn this off - but I'll leave it to
the Google devs to decide if this is worthwhile or not...

Gili

On Oct 24, 8:36 pm, "James Carman" <jwcar...@gmail.com> wrote:
> Can Jersey search the class hierarchy for the @Path annotation?
>
> On Fri, Oct 24, 2008 at 7:45 PM, je...@swank.ca <limpbiz...@gmail.com> wrote:
>
> > On Oct 24, 2:42 pm, Gili <gili.tzab...@gmail.com> wrote:
> >> Is it possible to tell Guice to avoid the use of CGLIB unless it's
> >> absolutely necessary? I know Guice uses it to solve circular
> >> dependencies but I use the Provider<Foo> approach instead. CGLIB
> >> proxies sometimes break compatibility. For example, today I ran into
>
> > Are you using method interceptors? We can't do them without CGLIB.




--
Cheers, Stuart

Gili Tzabari

unread,
Oct 27, 2008, 2:17:35 PM10/27/08
to google...@googlegroups.com

I think it is worth considering this on a higher level as well.
Proxies are supposed to mimic the underlying class as much as possible.
Did anyone investigate the implication of annotating the proxy with the
same annotations as the underlying class?

On the one hand I agree JAX-RS should probably check out the
superclass annotations. On the other hand, a proxy that doesn't mimic
the underlying class is a poor proxy ;) JAX-RS just went 1.0 so I don't
foresee them checking the superclass annotations anytime soon. It could
be easier to just fix this in Guice (if possible).

Gili

Stuart McCulloch wrote:
> 2008/10/27 Gili <gili.t...@gmail.com <mailto:gili.t...@gmail.com>>


>
>
> Hi James,
>
> I ran this question by the author of Jersey and he said that doing so
> would violate the JAX-RS specification:
> http://n2.nabble.com/com.sun.jersey.impl.uri.UriBuilderImpl.path()-throws-an-unexpected-exception-td1373393.html#a1381422

> <http://n2.nabble.com/com.sun.jersey.impl.uri.UriBuilderImpl.path%28%29-throws-an-unexpected-exception-td1373393.html#a1381422>


>
> I need to somehow tell Guice to not use CGLIB or to annotate the
> subclass with the same annotations as the superclass.
>
>
> looking at the codebase it appears Guice uses CGLIB's FastClass
> to create instances of public types when doing constructor injection,
> even if there's no circular dependency or interception going on, see:
>
> src/com/google/inject/DefaultConstructionProxyFactory.java
>
> afaik using FastClass here is just for performance, so it's technically
> possible to add some sort of switch to turn this off - but I'll leave
> it to
> the Google devs to decide if this is worthwhile or not...
>
> Gili
>
> On Oct 24, 8:36 pm, "James Carman" <jwcar...@gmail.com

> <mailto:jwcar...@gmail.com>> wrote:
> > Can Jersey search the class hierarchy for the @Path annotation?
> >
> > On Fri, Oct 24, 2008 at 7:45 PM, je...@swank.ca

> <mailto:je...@swank.ca> <limpbiz...@gmail.com


> <mailto:limpbiz...@gmail.com>> wrote:
> >
> > > On Oct 24, 2:42 pm, Gili <gili.tzab...@gmail.com

Brian McCallister

unread,
Oct 30, 2008, 11:21:23 AM10/30/08
to google...@googlegroups.com
On Fri, Oct 24, 2008 at 5:36 PM, James Carman <jwca...@gmail.com> wrote:
>
> Can Jersey search the class hierarchy for the @Path annotation?

Funny you mention this, I just wrote a bunch of stuff to search the
class hierarchy for method annotations -- luckily it only needs to be
done once per method, but it is less than pleasant.

I would consider it to be correct for Guice to add the annotations to
its generated proxies, but IIRC cglib doesn't generate things beyond
1.4 -- unless guice is using a super-secret version Chris hasn't told
us about yet!

-Brian

Chris Nokleberg

unread,
Nov 5, 2008, 7:53:04 PM11/5/08
to google-guice
No secret version, just the latest. CGLIB still runs on 1.2+ and
generates 1.2 bytecode. I plan to look into copying annotations to
generated subclasses as a option off by default. I did once before
(years ago) and it didn't pan out but honestly I don't remember why.

Gili Tzabari

unread,
Nov 5, 2008, 9:34:43 PM11/5/08
to google...@googlegroups.com

What about the option of having CGLIB totally disabled? Is this
targeted for 2.0 or was it later? The reason I ask is that I can foresee
problems copying annotations to sub-classes. Copying "marker
annotations" should work just fine but if an annotation processor agent
scanning for non-market annotations, which you end up copying, I'm
thinking it might end up modifying your CGLIB proxies by mistake.

Gili

Stuart McCulloch

unread,
Nov 6, 2008, 2:19:05 AM11/6/08
to google...@googlegroups.com
2008/11/6 Gili Tzabari <gili.t...@gmail.com>
       What about the option of having CGLIB totally disabled? Is this
targeted for 2.0 or was it later?

well going by the issue list:

   http://code.google.com/p/google-guice/issues/detail?id=230

shows it as accepted, but not yet scheduled for the next release...
 



--
Cheers, Stuart

Kamil Demecki

unread,
Nov 6, 2008, 4:57:47 AM11/6/08
to google-guice


On Nov 6, 8:19 am, "Stuart McCulloch" <mccu...@gmail.com> wrote:
> 2008/11/6 Gili Tzabari <gili.tzab...@gmail.com>
>
> >        What about the option of having CGLIB totally disabled? Is this
> > targeted for 2.0 or was it later?
>
> well going by the issue list:
>
>    http://code.google.com/p/google-guice/issues/detail?id=230
>
> shows it as accepted, but not yet scheduled for the next release...
> --
> Cheers, Stuart

+1 Imho Guice will be less invasive and can be applied to core of my
system (domain model)

Brian Pontarelli

unread,
Nov 6, 2008, 5:48:49 PM11/6/08
to google...@googlegroups.com
>
> +1 Imho Guice will be less invasive and can be applied to core of my
> system (domain model)

I've seen this a few times and wondered what people are injecting into
domains? Are you using a non-anemic domain and injecting other
domains or services into?

-bp

Gili Tzabari

unread,
Nov 6, 2008, 6:01:05 PM11/6/08
to google...@googlegroups.com

For example, I implement toString() as:

return objects.toString(this);

This walks all non-static fields using reflection and prints it out.
That's just one example (using helper functions).

Gili

Brian Pontarelli

unread,
Nov 6, 2008, 6:25:24 PM11/6/08
to google...@googlegroups.com
Interesting. I guess if you have absolutely no static method calls in
your code, this makes sense. Normally that type of thing is just put
into a toolkit similar to Math.

Anyone else doing something more transactional? Just wondering what
the cases are.

-bp

P.S. I'm a service-based guy, so I tend to favor anemic domains.

Anthony MULLER

unread,
Nov 7, 2008, 3:36:07 AM11/7/08
to google...@googlegroups.com
Other cases are cloning stuff or property handling... I have more cases but with interceptions and, as Guice creates CGLIB proxy to handle AOP, it is not usable for me because instance are no more serializable (a requirement in my case). So, Guice is not fully transparent.

Anthony


2008/11/7 Brian Pontarelli <br...@pontarelli.com>

Kamil Demecki

unread,
Nov 7, 2008, 6:28:18 AM11/7/08
to google-guice
http://www.infoq.com/articles/ddd-in-practice

"'Anemic Domain Model' where facade classes (usually Stateless Session
Beans) start accumulating more and more business logic and domain
objects become mere data carriers with getters and setters."

Hm, With anemic model you dont need injeting into model because it is
only data holder.

In non-anemic model there is model, services (ejb3) and many helpers
with support core model and have to be close it.

# Model

class Cat {
public boolean checkVirusRisk() { ... }
}

# Services

class CatService {
find();
save();
rent();
}

# Helpers

class VirusStrategy {
boolean isBlackListed();
}

class UsaVirusStrategy implements VirusStrategy {
@Inject connectionToFBI;
}


So when you create model and on next time client require you to invoke
service (without injecting you cant invoke service from model, unless
as parameter for method model) and you will have to move implemented
funtionality from Model/Helpers to Services which ends Anemic model
(all logic are in services).

In bussiness system there is many abstraction in core system:
connection to ldap, db, xml, many factories, authorization,
optymalization like caches, views, builders, kontrolers, managers
sessions and many other. I think support for this abstraction like IoC
close to core system it will be added value to system. Guice configure
system with defaults and in tests or during intergration with other
system you can ovverride some system policy (example for ldap).

Esko Luontola

unread,
Nov 7, 2008, 7:18:12 AM11/7/08
to google-guice
I just recently begun using Guice, so I have not yet faced those
problems, but since you say that the CGLIB proxies are not
serializable, it will probably cause problems in the framework I'm
building (http://dimdwarf.sourceforge.net/), because in it almost all
application objects must be serializable.

Brian Pontarelli

unread,
Nov 7, 2008, 12:23:04 PM11/7/08
to google...@googlegroups.com
>
>
> http://www.infoq.com/articles/ddd-in-practice

This article seems somewhat biased ;) He's making a lot of big
assumptions about SOA that aren't necessarily correct. This is
especially true with large distributed systems.


> "'Anemic Domain Model' where facade classes (usually Stateless Session
> Beans) start accumulating more and more business logic and domain
> objects become mere data carriers with getters and setters."

This is correct. Anemic means no logic with data.

> Hm, With anemic model you dont need injeting into model because it is
> only data holder.

Yeah.

> In non-anemic model there is model, services (ejb3) and many helpers
> with support core model and have to be close it.

Not necessarily. In a non-anemic pattern the domain model _is_ the
service. If you invoke a method on it the logic to fulfill that method
is part of the domain class. You can abstract the logic out into an
EJB (eeck - yes even with EJB3), but that's just an anemic proxy. The
domain object is doing little more than encapsulating a client call:

// Anemic
CatService cs = ...;
Cat cat = ...;
cat = cs.fix(cat);

// DDD
Cat cat = ...;
cat.fix();

public class Cat {
private final CatService cs;
private boolean isFixed = false;
@Inject public Cat(CatService cs) {
this.cs = cs;
}

public void fix() {
isFixed = cs.fix(this);
}
}

These are essentially the same in my book. I think what a lot of true
DDD and non-anemic folks are looking for is this:

// DDD
Cat cat = ...;
cat.fix();

public class Cat {
private final EntityManager em;
private boolean isFixed = false;
@Inject public Cat(EntityManager em) {
this.em = em;
}

public void fix() {
isFixed = true;
em.persist(this);
}
}

The code to change the state and save it to the database (or whatever
else is required) is part of the domain object itself.

Both of these DDD approaches encapsulates the state transition within
the cat, but state can be really nasty sometimes and you have also
lost the state of the cat prior to it being fixed unless you clone it
in the client code. Anemic model can fix this situation easily. Plus,
in a distributed system, if I'm passing around a non-anemic Cat, the
fix method might not be guaranteed to work if the remote CatService
isn't reachable or the EntityManager can't connect to the database
from that server. Therefore, the contract is broken. This means you
need an on-the-wire representation of the Cat (SDO, XML, value-object,
transfer-object) and a DDD representation inside the tiers of the
system. This requires some data translation between the transfer-
object and the DDD once the remote server receives the message.

I generally like to think that data and logic should be put as far
away from each other as possible. It doesn't necessarily bloat the
services code anymore than the domain would be bloated. Additionally,
I can have multiple ways to "fix my cat" without writing multiple
domains and they all work on the same data object. That's pretty nice.
This means you can go discover services for "fixing" cats based on the
types and you get a lot of other benefits.

>
> So when you create model and on next time client require you to invoke
> service (without injecting you cant invoke service from model, unless
> as parameter for method model) and you will have to move implemented
> funtionality from Model/Helpers to Services which ends Anemic model
> (all logic are in services).

There are a number of DDD frameworks that will fix this for you using
constructor AOP and other concepts. But in vanilla Java, yes, this is
an issue unless the DI container always creates instances of your
domain.

> In bussiness system there is many abstraction in core system:
> connection to ldap, db, xml, many factories, authorization,
> optymalization like caches, views, builders, kontrolers, managers
> sessions and many other. I think support for this abstraction like IoC
> close to core system it will be added value to system. Guice configure
> system with defaults and in tests or during intergration with other
> system you can ovverride some system policy (example for ldap).

Not sure I follow this bit.

-bp

Gili Tzabari

unread,
Nov 7, 2008, 1:23:18 PM11/7/08
to google...@googlegroups.com
Brian Pontarelli wrote:
> and you have also
> lost the state of the cat prior to it being fixed unless you clone it
> in the client code.

I don't understand this part of your reply. What do you mean?

> Anemic model can fix this situation easily. Plus,
> in a distributed system, if I'm passing around a non-anemic Cat, the
> fix method might not be guaranteed to work if the remote CatService
> isn't reachable or the EntityManager can't connect to the database
> from that server. Therefore, the contract is broken.

I don't agree with this statement. This is no different from you trying
to reach the database on the server end and it not being reachable for a
different reason (i.e. you've surpassed the maximum number of
connections or the database went down). In both cases your contract
needs to allow for failure when interacting with the database.

> This means you
> need an on-the-wire representation of the Cat (SDO, XML, value-object,
> transfer-object) and a DDD representation inside the tiers of the
> system. This requires some data translation between the transfer-
> object and the DDD once the remote server receives the message.

I don't agree that Rich Domain Models (non-amnemic in your terminology)
require you to pass rich models to the client. For example, you can use
ROA/REST for client-server communication and in that paradigm you only
pass the state back and forth. While it is true that ROA separates state
from behavior it is worth noting it eliminates the service layer
altogether (you're forced to use the same methods across all resources).

Gili

Brian Pontarelli

unread,
Nov 7, 2008, 2:35:18 PM11/7/08
to google...@googlegroups.com
On Nov 7, 2008, at 11:23 AM, Gili Tzabari wrote:


Brian Pontarelli wrote:
and you have also  
lost the state of the cat prior to it being fixed unless you clone it  
in the client code.

I don't understand this part of your reply. What do you mean?

If you have this code:

Cat cat = new Cat();
cat.fix();

You have lost the cat that wasn't fixed. You can remedy this by making Cat immutable:

Cat cat = new Cat();
Cat fixed = cat.fixed();
// cat is the original unfixed cat

Or by cloning:

Cat cat = new Cat();
Cat old = cat.clone();
cat.fix();




Anemic model can fix this situation easily. Plus,  
in a distributed system, if I'm passing around a non-anemic Cat, the  
fix method might not be guaranteed to work if the remote CatService  
isn't reachable or the EntityManager can't connect to the database  
from that server. Therefore, the contract is broken.

I don't agree with this statement. This is no different from you trying
to reach the database on the server end and it not being reachable for a
different reason (i.e. you've surpassed the maximum number of
connections or the database went down). In both cases your contract
needs to allow for failure when interacting with the database.

No it is different. What I'm saying is that if you pass around a Cat whose contract has the fix method on it, that method must be usable no matter where the cat instance is currently residing (i.e. which server it is on). If you pass that Cat instance to another server via Java Serialization or some other Serialization, that Cat needs to be "fixable" on that new server. If the fix method uses a service or a database, you can't guarantee that the database will be reachable on the new server.




This means you
need an on-the-wire representation of the Cat (SDO, XML, value-object,  
transfer-object) and a DDD representation inside the tiers of the  
system. This requires some data translation between the transfer-
object and the DDD once the remote server receives the message.

I don't agree that Rich Domain Models (non-amnemic in your terminology)
require you to pass rich models to the client. For example, you can use
ROA/REST for client-server communication and in that paradigm you only
pass the state back and forth. While it is true that ROA separates state
from behavior it is worth noting it eliminates the service layer
altogether (you're forced to use the same methods across all resources).

It doesn't require you to pass rich models across the wire and in fact you really shouldn't do this. In general Rich Domain doesn't separate state from behavior, so you need to do that by hand when you pass the state across the wire. It gets even more interesting if you are passing behavior across the wire (oh fun!). Let's do a simple example so we are on the same page with this distributed model:

Client ----> Server

- Client creates a Cat
- Client passes Cat to Server to be "fixed"

This is a standard distributed computing approach whether it is via a bus, service, tuple-space, whatever. 

RDO approach
--------------------
Okay, if you pass the Cat to Server, the Server can't call the fix method on the Cat, unless the service has been injected into the Cat such that it works on the Server (using my DDD code from previous post). Therefore, you probably want to have two Cat classes, one on the client and one on the server like this:

Client ----> Server
(Cat1)       (Cat2)

Then you need to pull the data out of the Cat1 and bundle it into another object to be passed across the wire. This might be an HTTP object, a XML object, SDO, whatever. I'll use Java Serialization and a transfer-object:

Client                 ------------------->             Server
(Cat1 into CatTO)            (CatTO)                    (CatTO into Cat2)

Okay, so now we have our RDO model that will correctly ensure that the Cat's contract is always correct because the fix method on Cat2 doesn't make a remote call, but instead writes out the Cat to the database.


Anemic approach
------------------------
The anemic approach ensures that the domain objects only contain data. Therefore, we can bundle up the Cat and just toss it across the wire since it is just a data holder (this gets tricky with versioning, but ignore that for now). This will look like this:

Client ----> Server
(Cat)       (Cat)

Since the client is simply invoking a service on the Server that takes a Cat, all is well. That Service can return a new Cat or something else entirely, doesn't matter because that object also only contains data.

-bp

Gili Tzabari

unread,
Nov 7, 2008, 2:57:11 PM11/7/08
to google...@googlegroups.com
Brian Pontarelli wrote:
> No it is different. What I'm saying is that if you pass around a Cat
> whose contract has the fix method on it, that method must be usable no
> matter where the cat instance is currently residing (i.e. which server
> it is on). If you pass that Cat instance to another server via Java
> Serialization or some other Serialization, that Cat needs to be
> "fixable" on that new server. If the fix method uses a service or a
> database, you can't guarantee that the database will be reachable on the
> new server.

Are you talking about wanting to be able to represent a Cat with fix()
on the server and without fix() on the client because of business-logic?
Or are you saying that technical limitations might cause fix() to fail
on the client? If it's the latter I argue that it's no different from
the server because even there the DB might become unreachable. If you're
arguing the former, then I argue you need different client-side and
server-side Cat interfaces because they are not really the same.

> It doesn't require you to pass rich models across the wire and in fact
> you really shouldn't do this. In general Rich Domain doesn't separate
> state from behavior, so you need to do that by hand when you pass the
> state across the wire.

I guess I am saying that you shouldn't be passing Rich Domain Objects
over the wire because (from practical experience) the server-side and
client-side interfaces are almost always "different enough" that you
can't share the interfaces. Clients usually contain a subset of the
server methods and might contain some client-only methods. I believe
Rich Domain Objects still hold a lot of value on the server-end, even if
you can't pass them to clients. Clients and servers can both run their
own show (with RDO) and communicate over the wire by passing a subset of
the state (DTO, REST, whatever you want to call it).

I argue you always need to define the client-server interface by hand.
Serializing your state-only Object to the client is very poor practice.
One reason is that you're essentially exposing an interface to the
client and this needs to be designed and exposed very carefully. The
other reason is that you can't rely on having Java on both ends of the wire.

Gili

Brian Pontarelli

unread,
Nov 7, 2008, 5:12:48 PM11/7/08
to google...@googlegroups.com
> Are you talking about wanting to be able to represent a Cat with
> fix()
> on the server and without fix() on the client because of business-
> logic?
> Or are you saying that technical limitations might cause fix() to fail
> on the client? If it's the latter I argue that it's no different from
> the server because even there the DB might become unreachable. If
> you're
> arguing the former, then I argue you need different client-side and
> server-side Cat interfaces because they are not really the same.

What I'm saying is that the fix method must be different on the client
and server. This generally means a different class for the client and
server. If it was the same class on the client and server, all the
logic would need to be pull out into a well known interface and that
interface would need to be different implementations on the client and
server, making the domain just a proxy and not very rich.


>
> I guess I am saying that you shouldn't be passing Rich Domain Objects
> over the wire because (from practical experience) the server-side and
> client-side interfaces are almost always "different enough" that you
> can't share the interfaces. Clients usually contain a subset of the
> server methods and might contain some client-only methods. I believe
> Rich Domain Objects still hold a lot of value on the server-end,
> even if
> you can't pass them to clients. Clients and servers can both run their
> own show (with RDO) and communicate over the wire by passing a
> subset of
> the state (DTO, REST, whatever you want to call it).

Yeah, we agree on this. You shouldn't be passing around rich domain
objects because they don't work that way. This incurs a lot of code
overhead though.


>
> I argue you always need to define the client-server interface by
> hand.
> Serializing your state-only Object to the client is very poor
> practice.
> One reason is that you're essentially exposing an interface to the
> client and this needs to be designed and exposed very carefully. The
> other reason is that you can't rely on having Java on both ends of
> the wire.

Not sure what you mean by this. You definitely have to define how your
client talks to the server and what your server responds with, since
that is the standard remoting paradigm. In terms of serializing a
state only object as poor practice, I think you might be confused,
because that's what you said you should do above with the DTO/REST/
whatever. DTOs are state objects.

Again, here's a concrete example so we are on the same page:

RDO
-------

public class ClientCat {
@Inject RemoteCatService cs;
boolean fixed;

public void fix() {
CatDTO dto = new CatDTO();
dto.fixed = this.fixed;
this.fixed = cs.fixTheCat(dto);
}
}

public class ServerCat {
@Inject EntityManager em;
boolean fixed;

public void fix() {
this.fixed = true;
em.persist(this);
}
}

public class CatDTO {
boolean fixed;
}

public class Client {
public void fixTheCat() {
ClientCat cat = DI.makeCat();
cat.fix();
}
}

// This class runs on a different server
public class RemoteCatService {
public void fixTheCat(CatDTO dto) {
ServerCat cat = DI.makeCat();
cat.fixed = dto.fixed;
cat.fix();
}
}


Anemic
----------

public class Cat {
boolean fixed;
}

public class Client {
@Inject RemoteCatService cs;

public void fixTheCat() {


Cat cat = new Cat();

cat = cs.fixTheCat(cat);
}
}

// This class runs on a different server
public class RemoteCatService {
@Inject EntityManager em;

public Cat fixTheCat(Cat cat) {
cat.fixed = true;
em.persist(cat);
return cat;
}
}


I like the second one personally. Less code and easy to manage. Plus,
I can pass my Cat around anywhere I want without transforming it into
other objects. In n-tiered systems, you could potentially pass the Cat
all the way from the front-end to the last tier and then back up. This
is how we built most stuff at Orbitz.

-bp

Gili Tzabari

unread,
Nov 7, 2008, 5:34:57 PM11/7/08
to google...@googlegroups.com

I am actually toying around with a 3rd paradigm. I'm not sure whether
it falls under the category of anemic models, rich domain model or
something else. Judge for yourself:

// Cat + business logic
class Person
{
private String name;

String getName();
Money calculateIncomeTax();
}

\-> Key point: all methods operate on the current Person. Unlike anemic
models, you store business logic methods at this level so long as they
apply to a single Person (i.e. calculateIncomeTax()).

// CatService + state
class People
{
private List<Person> people;

void marry(Person first, Person second);
List<Person> getMarriedPeople();
}

You would reuse the same Person implementation on both client and
server while varying the implementation of People. For your cats
example, you'd have Cat and Cats instead of Cat and CatService.

Gili

Brian Pontarelli

unread,
Nov 7, 2008, 6:06:48 PM11/7/08
to google...@googlegroups.com
A few questions:

1. Where is the implementation (actual code) for the Money calculateIncomeTax();  method located?

2. Why isn't the marry() method on Person like this: marry(Person other);?

-bp

Gili Tzabari

unread,
Nov 7, 2008, 6:51:10 PM11/7/08
to google...@googlegroups.com

I was actually going to bring up #2 myself in the last post but I
forgot. I believe that in most cases Person.marry(Person other) will
work but sometimes the implementation requires you to access information
that spans beyond the state of a single person. Because you never know
how the implementation might evolve over time I always prefer placing
such methods at the Persons level. That is, any business logic involving
a single person goes into Person while logic involving multiple parties
goes into People. That's just a rule of thumb (feel free to violate it
if it makes sense).

With respect to #1 I would suggest injecting two different
implementations of Persons for the client and server. That is, the code
lives inside the Persons instance, but the concrete implementation would
vary.

Again, I am sort of making this up as I go along but it feels right so far.

Gili

Brian Pontarelli wrote:
> A few questions:
>

> 1. Where is the implementation (actual code) for the /Money
> calculateIncomeTax(); method located?/
>
> 2. Why isn't the /marry()/ method on Person like this: /marry(Person
> other);/?

Brian Pontarelli

unread,
Nov 7, 2008, 7:46:48 PM11/7/08
to google...@googlegroups.com
In terms of the logic for the calculateIncomeTax method, it sounds
like that is going to be on the server. This means that the client
version of the Person class will primarily be a proxy to the server.
Therefore, it doesn't necessarily need to be "rich" because the logic
is not inside the class itself, but instead defined somewhere else.
All that you are gaining using a "rich" approach is that you get to
interact with just the Person class. Once you get to this point, there
is very little difference between this methodology and using anemic
domain and services.

On the flip-side, if you put the logic into the Person class itself
rather than on the server, you end up with a headache when the tax
laws change and you need to push out a new version of the Person class.

I guess that is my main point. The "rich" domain folks talk about
putting logic and data in the same place. But when the logic gets
complex or changes frequently, you _have_ to pull it out into a
service that conforms to an interface. Then it makes sense to put that
logic on another server so that it can be re-used and can scale. Then
you start looking at ways of swapping in new implementations of that
interface at runtime to make updates easier. And you think about
service discovery and all that jazz and BAM, your client is anemic.
You've pulled the logic as far away from the data as you could. Now,
you can still have a "rich" domain on the server. However, if you run
into similar cases on the server, you'll just do it again.

I also think this only applies in certain places. Those are business
domains with business logic. If it looks like to could ever be
distributed, I say make it anemic and service based.

-bp

Gili Tzabari

unread,
Nov 7, 2008, 9:37:40 PM11/7/08
to google...@googlegroups.com

Where is Martin Fowler when I need him? :)

Brian Pontarelli wrote:
> In terms of the logic for the calculateIncomeTax method, it sounds
> like that is going to be on the server. This means that the client
> version of the Person class will primarily be a proxy to the server.
> Therefore, it doesn't necessarily need to be "rich" because the logic
> is not inside the class itself, but instead defined somewhere else.
> All that you are gaining using a "rich" approach is that you get to
> interact with just the Person class. Once you get to this point, there
> is very little difference between this methodology and using anemic
> domain and services.

For this case there is indeed little difference between the anemic
model and rich model. But for this specific use-case I would flip the
question on you and ask: what do you benefit from a anemic model? Given
the point of using C-style functions and global variables versus OOP why
wouldn't you go for OOP every time?

> I guess that is my main point. The "rich" domain folks talk about
> putting logic and data in the same place. But when the logic gets
> complex or changes frequently, you _have_ to pull it out into a
> service that conforms to an interface.

You have to pull it into an interface, yes, but not necessarily into a
service. Nothing prevents you from defining an interface for
calculateIncomeTax() and providing different implementations in the form
of rich models.

> Then it makes sense to put that
> logic on another server so that it can be re-used and can scale. Then
> you start looking at ways of swapping in new implementations of that
> interface at runtime to make updates easier.

That's a requirement I never had in practice. My assumption has been
that if you have a fail-safe cluster in the first place then you just
update different servers at a time. I find the idea of swapping
implementations at runtime as a form of upgrading quite questionable. It
sounds like it would be much harder to update all necessary classes
atomically and track/log problems if something goes wrong.

> And you think about
> service discovery and all that jazz and BAM, your client is anemic.
> You've pulled the logic as far away from the data as you could. Now,
> you can still have a "rich" domain on the server. However, if you run
> into similar cases on the server, you'll just do it again.

If you absolutely need service discovery then I agree that pretty much
mandates anemic models, but again I question how frequently this
requirement comes up.

Gili

Brian Pontarelli

unread,
Nov 9, 2008, 1:27:51 PM11/9/08
to google...@googlegroups.com
> Where is Martin Fowler when I need him? :)

Man, Martin and I would probably blow each up if we got into it. :)

> For this case there is indeed little difference between the anemic
> model and rich model. But for this specific use-case I would flip the
> question on you and ask: what do you benefit from a anemic model?
> Given
> the point of using C-style functions and global variables versus OOP
> why
> wouldn't you go for OOP every time?

The anemic model will produce a well defined wire format that collects
all the data for a Person together. This allows that data to flow
through as many layers/tiers/servers as necessary and be worked on by
anything that understands that class of data. In the end, a large
distributed system is going to be a collection of functions that work
on classes of data.

I find myself coming back to this pattern more and more, but never
taking that step over to fully functional languages. I think the
reason is both due to the ability to organize and encapsulate in OO.
And, I would definitely not use C as a base line. There are many far
more elegant functional languages than C.

I also still use rich-objects at times. It is just not something I
force myself to use for everything. I find that model too restrictive
and not very pragmatic. But, there are still many benefits that I can
achieve from OO concepts like extension, aggregation, polymorphism and
the like. I just find that they also work well with anemic objects and
highly functional services. I guess in the end I don't find OO and
functions to be opposing ideals. They are tools I mix and match to
suit the task at hand.

One idea I've been tossing around lately is a new approach with a
separation of data and function. Not sure what it would look like or
how it would work, but it seems interesting to me. It would allow you
to define a data class such as Human, but have that Human behave like
a Infant at one point in time and a Teenager later. In the reverse,
the Infant might need Human data, but also other data classes to
function properly. Then later on the Teenager might also need the
Human data, but other data to function.

Need to think about it for another year or so to figure it all out. ;)


>
> You have to pull it into an interface, yes, but not necessarily
> into a
> service. Nothing prevents you from defining an interface for
> calculateIncomeTax() and providing different implementations in the
> form
> of rich models.

There probably isn't much keeping us from doing this, even on the
wire. If you consider any service where the wire protocol has the data
and the operation together, you can imagine a system where on the
server the data is first set into the rich-domain and then the
operation is invoked on that same object. The key is to avoid DGC and
shared state. I personally don't use this model, but you could.
However, it will still tend towards anemia when the object on the
server starts to move logic into other locations and other servers.


> That's a requirement I never had in practice. My assumption has been
> that if you have a fail-safe cluster in the first place then you just
> update different servers at a time. I find the idea of swapping
> implementations at runtime as a form of upgrading quite
> questionable. It
> sounds like it would be much harder to update all necessary classes
> atomically and track/log problems if something goes wrong.

I just bring up service discovery and updates because in larger
distributed environments where you have up-time goals, you have to
have some strategy for this. In terms of swapping implementations at
runtime, it is definitely something that I've done in the past and it
works pretty well, if the system is architected correctly. Once your
users are global, you lose any windows for maintenance and this means
that you need to be able to upgrade the system at runtime.


> If you absolutely need service discovery then I agree that pretty
> much
> mandates anemic models, but again I question how frequently this
> requirement comes up.

I'd say that most larger distributed applications use service
discovery and runtime updating. That would just be my guess. The ones
I've worked on use it. BUT, that doesn't mean it isn't something that
can't be figured into other systems without a lot of overhead. More
languages are beginning to come around to the idea of multi-threading
as a core concept and some languages even see runtime updates in that
category as well. If you consider OSGi, JMS (Java Module System), and
languages like Scala, Haskel, and Erlang, you begin to see this
pattern. I find that systems designed this way are far easier to
maintain over the lifetime of the system.

-bp

Stuart McCulloch

unread,
Nov 9, 2008, 8:30:01 PM11/9/08
to google...@googlegroups.com
2008/11/10 Brian Pontarelli <br...@pontarelli.com>
FWIW this is exactly the motivation behind Qi4j - context based behaviour...

   http://www.qi4j.org/introduction.html

there's a mailing list (see http://www.qi4j.org/26.html for subscription/archives)
where the design is regularly discussed and refined, and if you're familiar with
DDD concepts then you should feel right at home

Rickard's also going to be presenting the latest updates at this year's Øredev

--
Cheers, Stuart

Brian Pontarelli

unread,
Nov 10, 2008, 1:06:11 PM11/10/08
to google...@googlegroups.com

One idea I've been tossing around lately is a new approach with a
separation of data and function. Not sure what it would look like or
how it would work, but it seems interesting to me. It would allow you
to define a data class such as Human, but have that Human behave like
a Infant at one point in time and a Teenager later. In the reverse,
the Infant might need Human data, but also other data classes to
function properly. Then later on the Teenager might also need the
Human data, but other data to function.

Need to think about it for another year or so to figure it all out. ;)

FWIW this is exactly the motivation behind Qi4j - context based behaviour...

   http://www.qi4j.org/introduction.html

there's a mailing list (see http://www.qi4j.org/26.html for subscription/archives)
where the design is regularly discussed and refined, and if you're familiar with
DDD concepts then you should feel right at home

Took a look and it is definitely an interesting pattern. I did some work back in 2001-2002 with something similar to this built on top of Dynamo's container. It was more of a code generation approach, but similar. I like mixins a lot as a pattern in Java.

I still think there is some advantage to moving some of this into the language. I haven't figured out how to do it yet, but I think it could work well.

-bp

Kamil Demecki

unread,
Nov 12, 2008, 12:29:02 PM11/12/08
to google-guice
Thanks for reply both. I have read disccusion and have thoughts.

I think Model could be:

1) a well defined wire format (serializable, viewable)
2) good start point to make decision with inheritance instead of "if"
in services

I think using model only for sending data is wasting time and forcing
to duplicate code. I many situations one class is using in many
aspects (send data, view data, populate date) and model has much more
granularity in opposite to services.

Cat
- chooseShampoo() { if (virusStrategy.needAddtionalCheck())
{ ... } ... }
BrownCat
- chooseShampoo() { ... }
BlackCat
- chooseShampoo() { if (fortuneTeller.isAnimalOK(this) and if
(usaVirusStrategy.checkInFbi(this)) { ... } ... }

Earlier I didn't know that Guice sometimes creates proxy so I create
even serializable objects in guice. Now I will use GuiceFacade in
Model like GuiceFacase.inject(this).

In services similiar problem ends with many "if" (services are not so
modular)

CatService
- if (cat instance of BrownCat) {
...
} else if (cat instance of BlackCat) {
if (fortuneTeller.isAnimalOK(this) and if
(usaVirusStrategy.checkInFbi(this)) { ... } ...
} else {
if (virusStrategy.needAddtionalCheck()) { ... } ...
}

Cat is serializable entity so hibernate get from database rigth
inheritance (blackcat or other specjalization).

I dont want using many "if". One solution is above, so model has
access to interfaces (!) of services, kontrollers, views and how these
interfaces are implemented is outside decision (choosen could some
exception on client, but on server not).

Other solution to OO without "if" which comes to my mind:

CatService
- selectorService = InheritanceSelelctor.choose(cat,
ShampooSelector.class) { Class.forName(ShampooSelector.getName() +
cat.getClass().getSimpleName());
selectorService.chooseShampoo(cat);
ShampooSelectorCat implements ShampooSelector (service)
- if (virusStrategy.needAddtionalCheck()) { ... } ...
ShampooSelectorBrownCat implements ShampooSelector (service)
- ...
ShampooSelectorBlackCat implements ShampooSelector (service)
- if (fortuneTeller.isAnimalOK(this) and if
(usaVirusStrategy.checkInFbi(this)) { ... } ...

What do you think ? ;>


Kamil Demecki

unread,
Nov 12, 2008, 12:33:07 PM11/12/08
to google-guice


On Nov 7, 6:23 pm, Brian Pontarelli <br...@pontarelli.com> wrote:
>
> > In bussiness system there is many abstraction in core system:
> > connection to ldap, db, xml, many factories, authorization,
> > optymalization like caches, views, builders, kontrolers, managers
> > sessions and many other. I think support for this abstraction like IoC
> > close to core system it will be added value to system. Guice configure
> > system with defaults and in tests or during intergration with other
> > system you can ovverride some system policy (example for ldap).
>
> Not sure I follow this bit.
>
> -bp

I my small experience technical layer is so big as pure business
layer, or even larger. I think fine solution like Guice is good for
these kinds of problems.

Kamil Demecki

unread,
Nov 12, 2008, 12:36:12 PM11/12/08
to google-guice
Very nice. I'll Take a look. Half a year I checked DDD solutions to my
masters but I didnt find QI4J.

francisco treacy

unread,
Nov 12, 2008, 12:50:43 PM11/12/08
to google...@googlegroups.com
if you do DDD you might be interested in salve:
http://code.google.com/p/salve/ , which you can use with guice

francisco

Kamil Demecki

unread,
Nov 13, 2008, 5:30:30 AM11/13/08
to google-guice


On Nov 12, 6:50 pm, "francisco treacy" <francisco.tre...@gmail.com>
wrote:
> if you do DDD you might be interested in salve:http://code.google.com/p/salve/, which you can use with guice
>
> francisco
>


I saw this earlier and is nice ;> but

"Although already usable, Salve is still in its infancy. Not all
features have been implemented and not all problems worked out." -
where this unresolved features are described ? There is no entries on
Issues http://code.google.com/p/salve/issues/list

francisco treacy

unread,
Nov 13, 2008, 6:13:22 AM11/13/08
to google...@googlegroups.com
yup, it's a disclaimer, and perhaps there should be more issues.

but it's pretty straightforward - i've used it for months now (along
with guice) and it works like a charm. to reassure you, it's not one
of those abandoned projects that no-one uses. now, at your own risk :)

francisco

Kamil Demecki

unread,
Nov 14, 2008, 4:59:36 AM11/14/08
to google-guice


On Nov 13, 12:13 pm, "francisco treacy" <francisco.tre...@gmail.com>
wrote:
> ...and perhaps there should be more issues.
> > ... There is no entries on
> > Issueshttp://code.google.com/p/salve/issues/list
>
>


I think it is good idea ;> Raise issues to only touch on problems you
run. Class weaving is subtle theme so describing potential risk with
your framework is really good idea.
Reply all
Reply to author
Forward
0 new messages