I like to build a REST server that uses dependency injection. In my case the requirements would be
1) Not the services shall be injected, but the dependency they use
2) The services should be discovered via ServiceLoad and not written predefined in the web.xml
As an example:
I have the following project structure
project-base
contains the API, such as TheServiceInterface and TheDaoInterface
project-service-plugin
A plugin - contains a service implementation like
Path("foo")
public class TheService implements TheServiceInterface {
private TheDaoInterface dao;
#Inject
public TheService(TheDaoInterface dao) {
this.dao = dao;
}
#POST
#Consumes(APPLICATION_JSON)
#Path("pr")
public void webmethod(String request) {
// do something with the request and dao
}
}
project-integration
Wiring things together. The idea here is to find all TheServiceInterface implementations via ServiceLoader and inject the dao implementation into them.
I tried Jersey and Guice: a perfect combination for writing RESTful APIs, but this uses Jersey 1 and it seems that Jersey 2 and Guice have some problems, or all examples I find is only where the services are injected or written in the web.xml
Is my approach possible - and if so how ? What technologies can be used of achieving it ?
If there is a framework helping or another jvm language like groovy, please let me know
Thanks
Related
In terms of objects created at run time by the application server, what is the difference between
making of a bean both an EJB and a JAX-RS resource
#Stateless
#Local
#Path("current")
public class Facade
{
#PersistenceContext
EntityManager entityManager;
#EJB
...
// methods
}
using two different beans
#Path("current")
public class Facade
{
#EJB
private MyEjb myEjb;
// methods
}
#Stateless
#Local
public class MyEJB
{
// methods
}
Thanks for your answers!
EDIT:
ahah maybe my real questions would be about what's the result of using jax-rs annotations on an EJB, but that' basically the same question I asked.
It works. But if we stick to Oracle specification, exposing an EJB as a Web Service (rest or soap) is a kind of quick solution, with you promising to revisit this approach in the nearest future :-)
Infact, again sticking to what Oracle say, the EJB should reside on the business layer, and the web service should be in the integration layer.
I am not arguing that exposing an EJB is a wrong approach, but just because it is quite easy to develop rest service in Java, I would create a façade class, and transform in a service. Then I would inject the EJB into the class, or by jndi lookup if it is a rest. To have better separation of concerns.
This way you don't end up with a single class stuffed with annotation, but you are introducing flexibility, and have an architecture that may evolve, for example maybe you can decide in the future to deploy the business layer on a dedicated machine...whatever.
I'm trying to figure out the options that I have for the architecture of my API project.
I would like to create an API using JAX-RS version 1.0. This API consumes Remote EJBs (EJB 3.0) from a bigger, old and complex application. I'm using Java 6.
So far, I can do this and works. But I'm not satisfied with the solution. See my packages disposition. My concerns are described after the code:
/api/
/com.organization.api.v1.rs -> Rest Services with the JAX-RS annotations
/com.organization.api.v1.services -> Service classes used by Rest Services. Basically, they only have the logic to transform the DTOs objects from Remote EJBs in JSON. This is separated by API version, because the JSON can be different in each version.
/com.organization.api.v1.vo -> View Objects returned by the Rest Services. They will be transformed in JSON using Gson.
/com.organization.api.services -> Service classes used by versioned Services.
Here we have the lookup for Remote EJBs and some API logic, like validations. This services can be used by any versioned of each Service.
Example of the com.organization.api.v1.rs.UserV1RS:
#Path("/v1/user/")
public class UserV1RS {
#GET
public UserV1VO getUsername() {
UserV1VO userVO = ServiceLocator.get(UserV1Service.class).getUsername();
return userVO;
}
}
Example of the com.organization.api.v1.services.UserV1Service:
public class UserV1Service extends UserService {
public UserV1VO getUsername() {
UserDTO userDTO = getUserName(); // method from UserService
return new UserV1VO(userDTO.getName);
}
}
Example of the com.organization.api.services.UserService:
public class UserService {
public UserDTO getUsername() {
UserDTO userDTO = RemoteEJBLocator.lookup(UserRemote.JNDI_REMOTE_NAME).getUser();
return userDTO;
}
}
Some requirements of my project:
The API have versions: v1, v2, etc.
The different API versions of the same versioned Service can share code: UserV1Service and UserV2Service using UserService.
The different API versions of different versioned Services can share code: UserV1Service and OrderV2Service using AnotherService.
Each version have his own View Object (UserV1VO and not UserVO).
What botters me about the code above:
This ServiceLocator class it not a good approach for me. This class use legacy code from an old library and I have a lot of questions about how this class works. The way to use the ServiceLocator is very strange for me too and this strategy is not good to mock the services for my unit tests. I would like to create a new ServiceLocator or use some dependency injection strategy (or another better approach).
The UserService class is not intended to be used by another "external" service, like OrderService. It's only for the UserVxService. But in the future, maybe OrderService would like to use some code from UserService...
Even if I ignore the last problem, using the ServiceLocator I will need to do a lot of lookups among my code. The chance of create a cyclic dependency (serviceOne lookup serviceTwo that lookup serviceThree that lookup serviceOne) is very high.
In this approach, the VOs, like UserV1VO, could be used in my unversioned services (com.organization.api.services), but this cannot happen. A good architecture don't allow something that is not allowed. I have the idea to create a new project, like api-services and put the com.organization.api.services there to avoid this. Is this a good solution?
So... ideas?
A couple of things that I see:
The UserService should ideally be based off an interface. They seem to have a similar contract, but the only difference are their sources (RemoteEJB, LocalServiceLocator). These should be returning DTOs
UserV1Service extends UserService should not use inheritance but should instead favour composition. Think about what you'd need to do for v2 of the same service. Based on your example, you'd get UserV2Service extends UserService. This is not ideal especially if you end up with abstract methods in your base class that is specific for one version. Then all of a sudden other versioned services need to cater for this.
For the ServiceLocator
You're better off using a dependency injection framework like Spring or perhaps CDI in your case. This would only apply to your own code if your project is new.
For the ones that are hard to unit test, you'd wrap the RemoteEJB calls into it's own interface which makes it easier to mock out. The tests for RemoteEJBs would then be integration tests for this project.
The UserService class is not intended to be used by another "external" service, like OrderService. It's only for the UserVxService. But in the future, maybe OrderService would like to use some code from UserService
There is nothing wrong with Services on the same layer to talk to each other.
In this approach, the VOs, like UserV1VO, could be used in my
unversioned services (com.organization.api.services), but this cannot
happen. A good architecture don't allow something that is not allowed.
I have the idea to create a new project, like api-services and put the
com.organization.api.services there to avoid this. Is this a good
solution?
Just because you "could" do something doesn't mean that you should. While it might seem like a good idea to separate the layer into it's own project; in reality nothing stops a developer from either recreating the same class in that project or including the jar in the classpath and using the same class. I'm not saying that splitting it is wrong, just that it should be split for the right reasons instead of "what if scenarios".
I end up with this solution (thanks #Shiraaz.M):
I remove all extends in my Services and delete the dangerous ServiceLocator class. This inheritances without a good purpose and service locator are both bad ideas. I try to use Guice to inject the dependencies in my REST resources, but it's not so easy to do that in my Jax-rs version. But my services are very simple and easy to create, so my solution was simple:
#Path("/v1/user/")
public class UserV1RS {
private UserV1Service userV1Service;
public UserV1RS() {
this.userV1Service = new UserV1Service();
}
// only for tests!
public UserV1RS(UserV1Service userV1Service) {
this.userV1Service = userV1Service;
}
#GET
public UserV1VO getUsername() {
UserV1VO userVO = this.userV1Service.getUsername();
return userVO;
}
}
And my UserV1Service:
public class UserV1Service {
private UserService userService;
public UserV1Service() {
this.userService = new UserService();
}
// for tests
public UserV1Service(UserService userService) {
this.userService = new UserService();
}
public UserV1VO getUsername() {
UserDTO userDTO = userService.getUserName();
return new UserV1VO(userDTO.getName);
}
}
With this strategy, is easy to user other services with composition.
If necessary, in the future, I will introduce Guice to inject the dependencies in the rest resources and services (at least, in the services) and remove the default constructor from the services that have dependencies and using the same constructor in the tests and production.
About the item 4, I talked with the team and explain how is the organization. The team understand well this and no one break this architecture.
I have this scenario where i have my EJB3 beans in a jar file, deployed successfully to Jboss EAP-6.4.
Then I have another web project that looks up these EJB's inside a REST POJO class. I can currently access the EJB's from inside the web project using #Inject and #EJB, but my use case is one that i don't know which beans i need to load until runtime and the list is not static, so i might need to lookup 10 EJB's or none for a particular request etc.
I know I can possibly use
InitialContext.lookup('ejb:/.....')
to retrieve my EJB beans from inside the web project, but is there a way that i can retrieve them without that round trip(i believe), or maybe what am just looking for is a more elegant way to do EJB look-up at runtime just like the statically typed #EJB and #Inject versions.
Any suggestions are greatly appreciated.
EDIT
In my REST POJO classes i don't want to hard code any #Inject or #EJB annotations, rather i want that when a request comes in i look-up(for lack of better word) the EJB's that will handle the request, so all the decision is made at runtime really, as shown below
#Path("/path")
public class TestService {
#GET("/{id}")
public String loadGetPath(#Param id int id){
//at this point i want to dynamically resolve the EJB based on
//the value of id
}
}
Whoopdicity blog: Developing a dynamic JEE service client with CDI seems to have what you are looking for. At the end it claims you can do:
public class MyServiceConsumer {
#Inject #ServiceClient
private MyBusinessService service;
...
}
Instead of
public class MyServiceConsumer {
#EJB(lookup="...")
private MyBusinessService service;
...
}
I've been searching for hours to find a solution for my problem but I can't get it to work. I want to inject my Weld-managed service into a ConstraintValidator that is used to validate a User-Object that is posted to my JAX-RS Rest-Service. Everything is deployed to a glassfish 4.1 server.
I have a Service like this
#ApplicationScoped
public class UserService {
}
and I want to inject it into a ConstraintValidator like this
public class UniqueUserNameValidator implements ConstraintValidator<UniqueUserName, ApiUser> {
#Inject
private UserService service;
#Override
public void initialize(UniqueUserName constraintAnnotation) {
}
#Override
public boolean isValid(ApiUser value, ConstraintValidatorContext context) {
return service.getByUserName(value.getUserName()) == null;
}
}
the REST resource looks like this
#Path("users")
#Produces(MediaType.APPLICATION_JSON)
public class UserResource {
#Inject
UserService userService;
#POST
public Response createUser(#Valid ApiUser apiUser) {
ApiRepresentation created = userService.create(apiUser);
return Response.created(createURL(created)).build();
}
}
When I Post a json user object i get the following exception:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=UserService,parent=UniqueUserNameValidator,qualifiers={},position=-1,optional=false,self=false,unqualified=null,173822971)
at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74)
at org.jvnet.hk2.internal.Utilities.justInject(Utilities.java:947)
at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:902)
at org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:977)
at org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:968)
at org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:173)
I'm aware that jersey uses hk2 as DI provider and the ConstraintValidator is created using the InjectingConstraintValidatorFactory which in return uses the ResourceContext. Since HK2 doe know nothing about my WELD container managed beans it can not inject the proper service when creating the ConstraintValidator.
To fix this I am searching for
a) A way to provide JAX-RS (preferable a pure JAX-RS way without a dependency to jersey) with a custom ConstraintValidatorFactory to create the validator.
or
b) A way to force jersey to use WELD as the DI provider or tell hk2 to pickup all container managed beans WITHOUT manually adding every single bean to hk2.
I have no Idea how to use the bridge proposed here .
I appreciate any help.
Cheers
I also faced this issue with Jersey 2.25.x, Weld 2.4.x and Tomcat 8.x and haven't found a proper solution with #Inject.
As a workaround, I programmatically looked up for the bean instance using:
SomeSortOfBean bean = CDI.current().select(SomeSortOfBean.class).get();
Do you have the possibility to change the underlying JAX-RS implementation for your project?
When I had the same problem, I just switched from Jersey to RestEasy (fully certified JAX-RS implementation). http://resteasy.jboss.org/
Changing the implementation was easy enough: Just include the dependy through your favorite build automation tool (I use gradle):
compile 'org.jboss.resteasy:resteasy-servlet-initializer:3.0.11.Final'
Additionally, to make CDI work, include the resteasy-cdi JAX-RS CDI bridge:
compile 'org.jboss.resteasy:resteasy-cdi:3.0.11.
Lastly if you want the same JSON format, include the resteasy-jackson-provider:
compile 'org.jboss.resteasy:resteasy-jackson-provider:3.0.11.Final'
In the end, switching to resteasy gave me a lot less headache than trying to implement a Jersey fix.
I have a bunch of dependencies written as fast binary web services (aka Ejb3.1). Here is the service delcaration:
#Remote
public interface MyService {...}
You would inject an EJB into a servlet or managed bean with the following syntax:
#EJB
MyService myService;
I don't want to use the #EJB injection however. I'd like to use plain vanilla CDI:
#Inject
MyService myService;
One way to accomplish this would be to Create a #Produces method for every EJB:
#Produces MyService produceMyService(InjectionPoint ijp){
//jndi lookup for MyService interface
}
However, InjectionPoint is capable of giving you all the information you need, such as the target class name (MyService in this case).
Is there a way in CDI to do something like this? I'd want to call this producer last, if the required injection point couldn't be fulfilled in any other manner.
#Produces Object produce(InjectionPoint ijp){
Class ejbInterface = ijp.getType();
//jndi lookup for ejbInterface
}
This is a confusing post, so ask clarification questions. Thanks a ton!
Assuming that I understood your question (see comment): No, there is no API for this.
Good news is that there is a way to achieve this - but you probably don't want to do this at runtime, that's rather a task for application startup.
The CDI extension mechanism offers you some well defined hooks into bean processing at container startup. This is a perfect place for logic that decides about enabling / disabling of certain managed beans (probably based on static classpath information).
Have a look at function and implementation of Seam Solder's #Requires. That should be pretty close to your use case...