Adam Bien's Weblog

Wednesday Sep 15, 2010

How To Deal With Interfaces In Java EE 6 (or no more Impl)

In EJB 3.0 interfaces were required. So whether you liked it or not, you had to provide one. To make it look a bit natural, you could remove the "Remote" or "Local" suffix. This naming convention was redundant, because the interface had to be directly or indirectly annotated with @Local or @Remote annotation.

public interface CrudService {

}

The name of the Session Bean ended with the "Bean" suffix. It was more a workaround, than a best practice. Whenever possible, I would name it after its responsibilities, e.g. JPACrudService.

@Stateless
@Local(CrudService.class)
public class CrudServiceBean implements CrudService {
}

In Java EE 6 interfaces became absolutely optional. Neither in EJB 3.1, nor CDI / JSR-330 you need interfaces. You can inject classes directly. They will be still proxied, so all aspects like persistence, transactions, interceptors, decorators are still available. So you are no more forced to implement interfaces by the container. In Java EE 6 the same example would like this:

@Stateless
public class CrudService {
}

For the consumer (the injection point) the implementation would look like the interface. In worst case you could still introduce an interface without any problems. In recent Java EE 6 projects we didn't used interfaces (they were actually forbidden) in general. They were used intentionally as a concept, not as a general rule. They were used for:

  1. Strategy Pattern: there are already several implementations of an algorithm or concept
  2. Layering: there is a clear need to hide e.g. an ugly implementation of a legacy framework
  3. API (not very common): you have to expose a API, which gets implemented by SPI (e.g. JDBC)

Even for decoupling purposes, interfaces are no more needed. You can expose an EJB 3.1 / CDI bean directly over SOAP, Hessian or REST without any interfaces:

@Stateless
@Path("orders")
public class OrdersResource {}


If you introduce interfaces intentionally - and not as a general rule, you will considerably reduce the number of files. Your code becomes easier to understand and so maintain. An interface will become an artifact to hide multiple implementations and not a general plumbing.

There are always exceptions from the rule. If your are building products, frameworks, containers or platforms the need for extensibility is greater, than in standard (enterprise) projects.

"Contract First", "Coding To Interfaces" or "Decoupling" is not a reason to introduce an interface for everything - its just a fancy term. The answer to the question like: "We have to decouple this legacy adapter, because..., so an interface is a good idea at this place" is a true explanation of a requirement.


NEW workshop: Microservices with Java EE 7 and Java 8, January 26th, 2015, Airport Munich

A book about rethinking Java EE Patterns

Comments:

Mostly agree with what you're saying here. It's certainly more feasible now that mocking frameworks can mock concrete classes.

Posted by sboulay on September 16, 2010 at 07:24 PM CEST #

@Sboulay,

then you agree entirely? :-)

So far this approach works great in several projects. So far didn't found any disadvantages...

thanks for your comment!,

adam

Posted by adam-bien.com on September 16, 2010 at 09:00 PM CEST #

+1

In Java, Separate Interfaces have been abused - and principles like "Coding to Interfaces" widely misunderstood.

Java EE 6 still forces an arbitrary (and unnecessary) design constraint, though: component classes cannot be made final. Technically, there is no need for that anymore, since in Java SE 6 Java agents can be loaded programatically, and they can transform final classes before they are loaded. I would like to see this design restriction removed in Java EE 7.

Posted by Rogério on September 17, 2010 at 05:26 PM CEST #

@Rogerio,

thanks for your opinion!
I guess the "final" constraint was introduced to give more freedom for the spec implementors.

Do you really consider the "non-final" as a true design constraint in real world? Inheritance in EJB 3.1 and CDI components is less common, than e.g in JPA.

thanks!,

adam

Posted by adam-bien.com on September 18, 2010 at 05:50 PM CEST #

Hi,

I suppose it depends on how you think about your application when you are building it.
I work on integrating a product into clients systems and adding modules to implement specific requirements and thus treat pretty much everything I do as a "products, frameworks, containers or platforms". I don't really see why you would not do this for everything you write.

I agree that if you 100% know that the code you write with never EVER be used for anywhere else except in its current project then not programming to interfaces is fine but I am not sure how you can be sure of this.

The worst case would be moving your code out of a container in which case you would need to implement a replacement for the EJB in which case all your "consumers" of the EJB would need to be rewritten. Again not a problem if you 100% don't need to do this.

Posted by Owen on September 20, 2010 at 02:20 PM CEST #

If you want to do the "traditional" client/server setup, you still need a client JAR with interfaces, right? Assuming IIOP?

Posted by Fnord on September 20, 2010 at 05:15 PM CEST #

@Fnord,

absolutely: for a "traditional" communication style (remote EJBs), you will need a Remote interface. For pure IIOP communication even a RemoteHome. However: for REST, SOAP or e.g. hessian: (http://www.adam-bien.com/roller/abien/entry/ejb_3_1_hessian_almost) interfaces are not required.

For the definition of "strict" local API, interfaces are still a good choice, abstract classes, however, are sometimes even better for that purpose...

thanks!,

adam

Posted by adam-bien.com on September 20, 2010 at 06:01 PM CEST #

In a distributed system's development (jee6), it might be the case that a client developer is geographically separated, for some reason also restricted to see the actual bean implementation.
The client developer would surely not be able to guess the methods unless the REST or WSDL is published, thus in that scenario wouldn't the interface rescue the poor guy in such situation?! or I missed something :)

Cheers
Shiraz

Posted by Shiraz on September 28, 2010 at 09:23 PM CEST #

With regard to the final constraint I think it would be useful to have an @Final annotation that is enforced at compiler level rather than at JVM level. That way you can still tell other programmers 'don't override this method or you will break stuff' without restricting the containers ability to proxy the class.

Posted by Stuart Douglas on October 12, 2010 at 10:55 AM CEST #

Hi Adam,

how would you separate Local and Remote Aspects of a "Bohne" (*smile*)?

So you have often mentioned in your talks, that we could use an Local-Interface (to use inside the current layer) and a Remote-Interface (to offer to another layer) and merges them together in one simple Implementation:

@Remote
public interface SomeService {
public String greet();
}

@Local
public interface SomeLocalService extends SomeService {
public String greetAndMeet();
}

@Stateless
public class DefaultSomeService implements SomeLocalService {
// ...
}

Well, interfaces are OPTIONAL, but I'm very interested in an explanation...

Regards,
Robert

Posted by Robert on November 12, 2010 at 11:16 PM CET #

I'm still heavily using interfaces for some parts, e.g. backend services. And I put them even in a separate maven module. My impls are in another maven module which is only available with <scope>runtime. Thus I can force my co-workers to not do any dirty tricks and access internal implementation specific details.

Of course for a small project this makes no sense. But once you need to deal with 300++ services it does!

LieGrue,
strub

Posted by struberg on November 22, 2011 at 08:22 PM CET #

Post a Comment:
  • HTML Syntax: NOT allowed
realworldpatterns.com
...the last 150 posts
...the last 10 comments
License