jersey spring autowiring nullPointerException - spring

I have a session-scoped bean (Ama04Service) in Spring that is set within the web context. I have a task that runs as a Callable, and I need access to this bean from jersey web services. How should I accomplish this? If I simply attempt autowiring the bean the first call of Ama04ServiceImpl (public Response verifNum) the autowiring run successfully, then if i call an another method (clickReponse) in the jersey web service(Ama_04Service) I get NullPointerException
this looks like sprine re-instantiate the autowired bean
please any idea ?
thanks in advance.
The session-scoped bean I am injecting looks like this:
Service("ama04Service")
#Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
#Transactional(readOnly = false)
public class Ama04ServiceImpl implements Ama04Service, LineListener {
////some code here//////
}
the jersey web service that calls session-scoped bean looks like this
#Path("/ama04")
public class Ama_04Service {
#Autowired
Ama04Service ama04Service;
#Autowired
Ama01Service ama01Service;
#Autowired
Ama03Service ama03Service;
#Autowired
ResourceBundleService resourceBundleService;
#GET
#Path("/quest/{date}/{numDonn}/{language}")
#Produces(MediaType.APPLICATION_JSON)
public Response verifNum(#PathParam("numDonn") final String numDonn,
#PathParam("date") final String date,
#PathParam("language") final String language) {
///////// some code here///////
#GET
#Path("/clickRepons/{numDonn}/{occRep}/{occ}/{date}/{language}")
#Produces("application/json; charset=UTF-8")
public String clickReponse(#PathParam("numDonn") final String numDonn,
#PathParam("occRep") int occRep, #PathParam("occ") int occ,
#PathParam("date") final String date,
#PathParam("language") final String language) {
Ama4 currentAma = new Ama4();
}

Related

Spring - Is it good to register request scoped bean at every request though code?

In Spring Web application, I have to use specific value from request object in another spring classes within application. Value is request specific value.
In the following example, is it good way to register value coming from Request Body every time and use #Autowired with #RequestScope annotation to use value in another spring(e.g. #Service) classes? Is it good to register RequestScopedType bean value for each request through BeanFactory?
#RestController
#RequestMapping("/")
public class VehicleServiceController {
#Autowired
private BeanFactory beanFactory;
#Autowired
private ServiceClass serviceClass;
#PostMapping(path = "/postDetails", consumes = MediaType.APPLICATION_JSON_VALUE)
public OutputPayload postDetails(
#RequestBody InputPayload inboundPayload) throws Exception {
beanFactory.getBean(RequestScopedType.class).setValue(inboundPayload.getType());
return serviceClass.methodToCall();
}
}
Will there be any impact on performance as load is very huge? Is there any another way to inject/get RequestBody object value(inboundPayload.getType())?
You don't have to do beanFactory.getBean(RequestScopedType.class). You can just simply autowire it #Autowired RequestScopedType requestScopedType.
Just don't forget to change the scope of the bean as Request.
#Component
#Scope(scopeName = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestScopedType {
But this begs another question, why over complicate things, why can't you pass inboundPayload.getType() to the serviceClass.methodToCall(); ?
What is stopping you from using it this way return serviceClass.methodToCall(inboundPayload.getType());

not able to replace spring bean with mock in camel route

using #Profile I am able to mock the spring bean, however in the camel route which mock bean method is not invoked. I am using SpringJUnit4ClassRunner.class and using #ActiveProfile
Below is the route in which I want to replace, cancelSubscriptionTransformer, myBeanClient, extendedClient beans with my mock beans in unit testing.
from("{{cancelSubscriptionFromRMQUri}}").routeId("cancelSubscriptionRoute")
.unmarshal().json(JsonLibrary.Jackson, Subscription.class)
.bean("cancelSubscriptionTransformer", "toKbCancelSubscription")
.choice()
.when().simple("${body.serviceType} == 'subscriptions'")
.bean("myBeanClient", "cancelSubscription(${body.subscriptionId}, ${body.createdBy}, ${body.reason}, ${body.comment})")
.bean("extendedClient", "retrieveSubscription(${body.subscriptionId}, ${body.externalKey})")
.marshal(json)
.to("{{cancelSubscriptionTORMQUri}}")
.when().simple("${body.serviceType} == 'usage'")
.bean("myBeanClient", "cancelSubscription(${body.subscriptionId}, ${body.dateTime},null, null, -1, ${body.createdBy}, ${body.reason}," +
" ${body.comment})")
.endChoice();
Below is how I define my ExtendedClientMock, I use the same approach for the rest of the mock beans
#Profile("test")
#Primary
#Repository
public class ExtendedClientMock extends ExtendedClient {
public Subscription retrieveSubscription(UUID subscriptionid, String sdpSubscriptionId) throws MyClientException {
Subscription subs=new Subscription();
subs.setProductName("test");
return subs;
}
}
Below is the code for unit testing:
#ActiveProfiles({"test", "aop"})
#AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2)
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = CancelSubscriptionRouteTest.class)
#EnableAutoConfiguration
#ComponentScan
#ContextConfiguration(classes = { BillingServicesApplication.class })
#UseAdviceWith
public class CancelSubscriptionRouteTest {
#Autowired
protected CamelContext camelContext;
#Autowired
private CancelSubscriptionTransformer cancelSubscriptionTransformer;
#Autowired
private ExtendedClient extendedClient;
#Autowired
private MyBeanClient myBeanClient;
#EndpointInject(uri = "{{cancelSubscriptionTORMQUri}}")
private MockEndpoint cancelSubscriptionTORMQUriEndpoint;
#EndpointInject(uri = "{{cancelSubscriptionFromRMQUri}}")
private ProducerTemplate cancelSubscriptionFromRMQUriEndpoint;
#Inject
private ObjectMapperContextResolver objectMapperContextResolver;
#Test
#DirtiesContext
public void testCancelSubscriptionRoute() throws Exception {
cancelSubscriptionTORMQUriEndpoint.expectedMessageCount(1);
ObjectMapper objectMapper= objectMapperContextResolver.getContext(ObjectMapperContextResolver.class);
String jsonString=objectMapper.writeValueAsString(subscription);
CancelSubscription cancelSubscription=cancelSubscriptionTransformer.toKbCancelSubscription(subscription);
Assert.assertEquals("mock auto created by amel",cancelSubscription.getComment());
cancelSubscriptionFromRMQUriEndpoint.sendBody(" {{cancelSubscriptionFromRMQUri}}",jsonString);
cancelSubscriptionTORMQUriEndpoint.assertIsSatisfied();
}
}
The Assert.assertEquals("mock auto created by amel",cancelSubscription.getComment()); gets statisfied by calling cancelSubscriptionTransformer.toKbCancelSubscription which is invoked on the mock bean. however when message is sent to cancelSubscriptionFromRMQUriEndpoint.sendBody, the route is invoked and the actual beans in the route are not being replaced by mock beans
#MickaƫlB looks like the issue was I was not extending the correct bean and also I had to use #Inject in my route builder spring bean and use bean name instead of string format of bean name
This is very old but I ran into this issue.
The answer is that instead of .Bean(MyBean.class, "myMethod"), you should use .to("bean:myBean?method=myMethod"). The reason is that the first way, Camel will instantiate the bean. The 2nd way, Spring has control of the bean and camel will look it up. Therefore you can use Spring mockBean to change it.
I'm using Camel version 3 now by the way, and beanRef is removed. If you used beanRef, replace it with .to("bean:myBean?method=myMethod).

Correct scope for spring beans on Rest Service

I'm creating a REST service using RestEasy and Spring 4.
The service is basically an endpoint for a complex batch process. So clients call the service passing a bunch of parameters and then the processing is triggered.
As there are many parameters that are initially passed to the service, and those parameters are used pretty much everywhere in the system, I've chosen to create a 'helper' bean that will hold the parameters, then every other bean can autowire the 'parameter bean' and use it.
example:
the url called by the client would be: http://localhost/rest/service/execute?processType=A&initialDate=20141220&finalDate=20141231......
The REST Service endpoint would be something like:
#Path("/service")
public class RESTService {
#Autowired
private RequestParams params;
#Autowired
private ProcessOrchestrator orchestrator;
#POST
#Path("/execute")
#Produces(MediaType.TEXT_PLAIN)
public Response executa(
#NotNull #QueryParam("processType") String processType,
#NotNull #QueryParam("initialDate") String initialDate,
#NotNull #QueryParam("finalDate") String finalDate,
...
) {
params.setProcessType(processType);
params.setInitialDate(initialDate);
params.setFinalDate(finalDate);
orchestrator.triggerBatchProcess();
}
}
The RequestParams bean will only hold the parameters values:
#Component
public class RESTService {
private String processType;
private String initialDate;
private String finalDate;
...
// getters and setters
}
And the other beans would #Autowire the params bean and use its parameters:
#Component
public class DataProcessor {
#Autowire
private RequestParams params;
//...
}
#Component
public class DataConverter {
#Autowire
private RequestParams params;
//...
}
#Component
public class FileWritter {
#Autowire
private RequestParams params;
//...
}
The design looks correct, right? Now, my concern is: how do I make sure that a new RequestParams instance is created every time the service is called? Do I need to declare a scope ("request" for instance) for all my beans?

How do I create a sub-resource with spring dependencies #autowired with apache cxf

I can't figure out how to get spring to autowire dependencies in a sub resource. I need to specify some request state to the sub resource. I'll also need access to cxf managed #Contexts.
If I have a class
#Path("/resource/")
public class Resource {
#Autowired
private dependency
#Path("{id}/sub/")
public getSub(#PathParam("id") String id){
// I know this is not right. I could autowire subresource, but it needs
// to be request scoped and I get errors about proxying request scoped bean
// into singleton bean.
// I have also tried instantiating the subresource using ResourceContext
// but then Subresource's dependencies don't get injected
return new Subresource(id);
}
}
And another class
public class Subresource{
#Context
private UriInfo uriInfo;
#Autowired
private Dependency2 dependency2;
private String id;
public Subresource(String id){
}
#GET
public Response get(){
return Response.ok(id).build();
}
}
How do I get the spring managed dependencies to be auto injected in the sub resources? How does the sub resource get access to CXF managed dependencies?
I create factory bean to instantiate sub-resource:
public class SubResourceFactory {
#Autowired
private AutowireCapableBeanFactory autowireBeanFactory;
public SubResource createBean(String parameter1, Parameter2 parameter2) {
... creating SubResource instance, setting parameters to it
autowireBeanFactory.autowireBean(subResource);
return (SubResource) autowireBeanFactory.initializeBean(subResource, "subResource");
}
}
AutowireCapableBeanFactory allows to init bean created outside of Spring Context and inject any Spring beans to it.
SubResourceFactory is instantiated as Spring singleton bean in my project and injected in Root Resource, so i can use it like this:
#Resource
private SubResourceFactory subResourceFactory;
#Override
public SubResource getInfoFromSubResource(String parameter1) {
Parameter2 parameter2 = parameter2StoreService.getParameter2(parameter1);
return subResourceFactory.createBean(parameter1, parameter2);
}
But this subResource is managed only by Spring, so You can inject only Spring beans, You can not inject CXF-RS #Context beans.
There must be a way to do same thing to allow Spring and CXF-RS injections with ResourceContext, but I can see now, that it injects only CXF-RS beans, no Spring at all.

How to get Spring WebContext in class annotated #controller

In Spring MVC with annotation, we mark any POJO with #Controller.
In this controller we can get WebApplicationContext, using autowired property.
#Controller
public class HomePageController {
#Autowired
ApplicationContext act;
#RequestMapping("/*.html")
public String handleBasic(){
SimpleDomain sd = (SimpleDomain)act.getBean("sd1");
System.out.println(sd.getFirstProp());
return "hello";
}
But in this approach we do not have servletContext handy with us. So is there way we can still use older way of getting WebApplicationContext ? i.e.
WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext)
How will we get servletContext here ?
I am not facing any compulsion to use old way; so this question is just out of curiosity to check flexibility of spring.
Also It can be a interview question.
You can just inject it into your controller:
#Autowired private ServletContext servletContext;
Or take HttpServletRequest as a parameter and get it from there:
#RequestMapping(...)
public ModelAndView myMethod(HttpServletRequest request ...){
ServletContext servletContext = request.getServletContext()
}
The following is correct approach :
#Autowired
ServletContext context;
Otherwise instead of auto wiring the ServletContext, you can implement ServletContextAware. Spring will notice this when running in a web application context and inject the ServletContext. Read this.
You can also do it inline:
#RequestMapping(value = "/demp", method = RequestMethod.PUT)
public String demo(#RequestBody String request) {
HttpServletRequest re3 = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
return "sfsdf";
}
You can implement an Interface from Spring called org.springframework.web.context.ServletContextAware
public class MyController implements ServletContextAware {
private ServletContext servletContext;
#Override
public void setServletContext(ServletContext servletContext) {
this.servletContext=servletContext;
}
}
Then you can use the servletContext any place in the class.
By accessing the session you can get the servlet context, sample code:
#Controller
public class MyController{
....
#RequestMapping(...)
public ModelAndView myMethod(HttpSession session ...){
WebApplicationContextUtils.getRequiredWebApplicationContext(session.getServletContext())
}
}
You can get the HttpSession from the HttpServletRequest also.

Resources