JAXRS resource: #Stateless or #RequestScoped - java

I've created a jaxrs resource like this:
#Path(ReferenceEndpoint.PATH)
public interface ReferenceResource {
#GET
public Response download(
#PathParam(ReferenceEndpoint.Download.Parameters.ID)
String id
);
}
I'm struggling with #Stateless and RequestScoped annotations.
javax.ejb.Stateless;
javax.enterprise.context.RequestScoped;
I figure out what are they stand for, but I don't quite figure out why I see them in some code over there.
I mean, I've took a look over there, and sometimes I see #Stateless, but other times, #RequestScoped, and sometimes netiher of them.
Any lights?

Related

"Bypassing" a mock in Quarkus unit testing

I have a Quarkus project where I have most of the business logic placed in services, aka injectable beans using #ApplicationScoped annotations, where all of the CRUD operations take place. In the JAX-RS resource files themselves, the bulk of the logic is just validation, often using whole validation beans. This has meant that we needed to mock our injected services when we tested the resources, to prevent the unit tests from becoming essentially integration tests. We do this having a structure like this (example project);
The file MockGreetingService.java in turn looks like this:
import io.quarkus.test.Mock;
import javax.enterprise.context.ApplicationScoped;
#Mock
#ApplicationScoped
public class MockGreetingService extends GreetingService {
#Override
public String sayHello(String name) {
return String.format("Hello %s, your id is %s", name, "1234");
}
}
Our actual project is a bit more sophisticated than this in the way that the mocks always return our DTO classes regardless of input, but the principle is the same as above. They work flawlessly for our JAX-RS resource tests. However, trying to test the actual service beans themselves means problems with this setup. I built a service test, which uses the same annotations and flow as the code below:
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
#QuarkusTest
public class GreetingServiceTest {
#Inject
GreetingService greetingService;
#Test
void checkReturnsHello () {
String result = greetingService.sayHello();
System.out.println(result);
Assertions.assertEquals("hello Martin! Your country is Italy", result);
}
}
With the dependency injection in the class above, which we don't do in our resource tests, I expected Quarkus to understand that we want to use the original service in this test. How foolish of me. A simple log has shown that the mock service methods indeed still run in the latter test above.
Now I wonder - is it a way to disable the mock for this latter test? Preferably without having to modify or remove the mock classes, although I realize that might not be possible in the way I imagine it to be. Thanks in advance!
Sounds like a use case for qualifiers, which enable you to have different implementation beans, and to choose at the injection point which type of bean you prefer:
https://jakarta.ee/specifications/cdi/2.0/cdi-spec-2.0.html#qualifiers
As an alternative, you may also decide to instantiate your service on your own, not using cdi in any way.

Trying to instantiate a bean with the CDI from a running webapplication

I have a jar that contains a #Stateless class defined like
#Stateless
public class TestBean() {
#Inject
AnotherBean bean2;
public String getThis() {
return bean2.getAString();
}
}
A webapplication (with a dependency on this jar) running on wildfly 10.1.0 would like to instantiate this bean and use its methods. The webapplication calling method might be a rest endpoint (called by some other webapplication) or just a regular java method.
What is the best way to instantiate TestBean? I have tried several solutions none of which works.
For example this one
Building a CDI 2 standalone
and this one
Does CDI work for regular Java application?
I am new to the CDI and how it works, I am wondering if this is explained well somewhere?
Its not really clear what your question is, but if you have JAX-RS resource, in the WAR file, then this should just work
#Path("/somePath")
#RequestScoped
public class SomeResource {
#Inject
private TestBean testBean;
#GET
public String doGet() {
return testBean.getThis();
}
}

How to annotate JAX-RS on an interface while using Jersey

This question had been asked a few times before, however the answers doesn't seem to work and/or Jersey has moved on with more changes.
I'm exposing some REST APIs using JAX-RS and Jersey (version 2.24). And I wish to annotate the interface with JAX-RS and a concrete implementation (without any annotations). However, since this patch Jersey stopped supporting this possibility. As far as I understand the spec, it doesn't strictly prohibit doing that.
If a subclass or implementation method has any JAX-RS annotations then all of the annotations on the superclass or interface method are ignored.
implying that it is totally okay to do that. In many cases it is good to use an interface, and have a server and client each have their respective implementations.
There are plenty of solutions out there,
Use a ResourceConfig and do a registerClasses(MyImplementation.class) . However, this doesn't work.
Disable the package scanning configuration in web.xml, create a custom javax.ws.rs.Application and do a register of your implementation from there. Doesn't work.
use a ResourceConfig and define a custom AbstractBinder and do a bind so that Jersey's dependency injection can find the concrete implementations. Doesn't work.
Use RESTEasy. RESTEasy doesn't seem to impose the interface restrictions as in Jersey. Never tried it myself.
I would appreciate if someone can share their experience with this. Any help on how to get Jersey working would be great too. As for the option (4) is it really necessary to switch ? A sample code below.
MyResource
package com.foo;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
#Path("/hello")
public interface MyResource {
#GET
public String sayHello();
}
MyResourceImpl
package com.bar;
public class MyResourceImpl implements MyResource {
#Override
public String sayHello() {
return "Hello Jersey";
}
}
Also have a web.xml that has the package scanning enabled to scan com.foo
If you want to separate Resource interface from implementation (allowing you to use the interface with some REST client like resteasy client) you can use #RequestScoped on the implementation. Thus, this bean could use injected resources like EJB, EntityManager, ...
Using your sample :
import javax.ws.rs.GET;
import javax.ws.rs.Path;
#Path("/hello")
public interface MyResource {
#GET
public String sayHello();
}
MyResourceImpl
package com.bar;
#RequestScoped
public class MyResourceImpl implements MyResource {
#Override
public String sayHello() {
return "Hello Jersey";
}
}
Nevertheless, you have to take into consideration that as soon as you use specific JAX-RS classes in your implementation code (like UriInfo, Response object, ...) you will create a coupling between your implementation and the JAX-RS API.
In Jersey,We should Put the class level #Path on the implementation instead of the interface.
package com.foo;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
#Path("/hello")
public interface MyResource {
#GET
public String sayHello();
}
MyResourceImpl
package com.bar;
#Path("/hello")
public class MyResourceImpl implements MyResource {
#Override
public String sayHello() {
return "Hello Jersey";
}
}

Singleton injected in Interceptor multiple instantiations

I am using JBoss EAP 6.4.10 in a project and I have set up a #Singleton with #Startup. This singleton is #Injected into an #Interceptor because I use some methods from it in the interceptor.
So far so good, it basically works, but what I noticed is that the #PostConstruct method of the #Singleton is not called once, nay it is called 496 times. So I wonder why this is happening. Cant I inject a singleton in an interceptor?
I figured out the problem. I had imported import javax.ejb.Singleton; instead of import javax.inject.Singleton;

#EJB workflowDao is null in service layer

I'm trying to figure out how to setup a Service/Dao layer in my application. I've found a few dozen resources all with different ways on how to do it and decided to follow the model found here: How should EntityManager be used in a nicely decoupled service layer and data access layer?
I can't figure out what I'm missing that's causing this NPE.
Usage:
#Path("/helloworld")
public class MyController {
#GET
#Produces(MediaType.TEXT_PLAIN)
public String TestRequest() {
Workflow workflow = new Workflow();
workflow.setName("test");
WorkflowService workflowService = new WorkflowService();
workflowService.save(workflow);
return "Workflow ID:";
}
}
My Dao:
#Stateless
public class WorkflowDao {
#PersistenceContext(unitName = "unit")
private EntityManager entityManager;
public int save(Workflow workflow) {
entityManager.persist(workflow);
return workflow.getId();
}
}
My Service:
#Stateless
public class WorkflowService {
#EJB
WorkflowDao workflowDao;
public int save(Workflow workflow) {
int id = workflowDao.save(workflow); //throws NullPointerException because workflowDao is null
return id;
}
}
This is my first time setting up a Java project (only have worked on 1 before and it used Spring) so please keep that in mind if this looks horribly wrong.
WorkflowDao is not an EJB, it's a POJO with a#Stateless annotation. So naturally, injecting it with #EJB fails, creating a null workflowDao attribute and eventually producing a NullPointerException.
To make WorkflowDao into a full-fledged EJB, besides having a #Stateless or #Stateful annotation it needs to implement a local, remote or both interfaces, and those interfaces must be annotated respectively with #Local and #Remote. Please refer to the tutorial for details.
Also, quite possibly (this can be application server-dependent) you'll have to register the EJB in the application's xml descriptor files - for instance, in web.xml's <ejb-local-ref> element.
As a side note - it's not a good idea to use an EJB as a DAO, an EJB is typically used for implementing business logic (true, persist/merge operations can be called from here) but the actual persistence layer nowadays is implemented using JPA. In other words, WorkflowService should be the EJB service, there's no need to inject an EJB into it, and there's no need for a separate DAO layer - JPA entities fulfill this role.
If you instantiate your WorkflowService manually, the container wont perform any injection, since your WorkflowService is not managed by the Container.
I suggest you:
Annotate your Jax-RS Resource #Stateless
Inject your WorkfloService via #EJB as a member
Implementing a Local or Remote Interface is not necessary anymore
#Path("workflows")
#Stateless
public class WorkFlowResource{
#EJB
WorkflowService workflowService;
#GET
#Produces(MediaType.TEXT_PLAIN)
public String TestRequest() {
Workflow workflow = new Workflow();
workflow.setName("test");
workflowService.save(workflow);
return "Workflow ID:";
}
}

Categories