Deploying CXF service endpoint with Spring dependency injection - java

I'm trying to inject spring bean into class annotated with #WebService and #SOAPBinding annnotations.
#WebService(targetNamespace = JAXWSMessageHandler.MY_URL)
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public class JAXWSMessageHandler {
private StorageManager bufferContainer;
public void setBufferContainer(StorageManager storageManager){
this.bufferContainer = storageManager;
}
and I get the following exception:
Service class soap.service.JAXWSMessageHandler method setBufferContainer part {http://myurl/myproject/v1}setBufferContainer cannot be mapped to schema. Check for use of a JAX-WS-specific type without the JAX-WS service factory bean.
It seems that the operation used by spring is expected to be defined in WSDL by CXF. I think I can hack it with singleton mediator class that would allow communication from WebService class to my business class,however, it doesn't sound good to me and I'd like to do that properly. Any hints how to do that?

JAX-WS is interpreting the method signatures on the annotated class as web service operations. My guess is that if you used constructor injection (instead of setter injection), the problem would go away.

I think I have a better solution:
Presumably you are using #WebMethod to annotate the methods you want to expose on your web service?
Well you can also add a #WebMethod annotation to your setter method, and set the attribute 'exclude' to be true. This means that this method will not be expected to be defined in your wsdl.
#WebService(targetNamespace = JAXWSMessageHandler.MY_URL)
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public class JAXWSMessageHandler {
private StorageManager bufferContainer;
#WebMethod(exclude=true)
public void setBufferContainer(StorageManager storageManager){
this.bufferContainer = storageManager;
}

Related

Dependency injection according to conditions

My controller:
#RestController
#RequestMapping("/mypath")
public class MyController {
#Autowired
MyServiceInterface service;
#PostMapping("/{source}")
void myControllerFunc(#PathVariable String source, #RequestBody MyObject obj) {
...
Object myServiceObj = service.myServiceFunc(param);
...
}
}
My Service Interface:
public interface MyServiceInterface {
Object myServiceFunc(String param);
}
My Service Implemantations:
#Service
public class MyServiceOne {
Object myServiceFunc(String param) {
...
}
}
#Service
public class MyServiceTwo {
void myServiceFunc(String param) {
...
}
}
My spring-boot version : 1.5.7
I want to inject the service according to my path variable ("source") . If source = one, inject MyServiceOne or if source = two, inject MyServiceTwo.
Is this possible?
It sounds like you need both of these to be available and each method invocation on the controller can choose a different one. So wire up both implementations, with a qualifier to distinguish them. Use the path variable in the controller method and let it decide programmatically which service to call.
I don't think it's possible and reasonable.
A #RestControllers is by nature a singleton. It gets configured at startup and remains the same for every request.
The expression /{source} is being evaluated during a request at runtime, when the controller has already been set up.
The options to consider:
Inject both services and, in the method, decide which one to pick.
Create two separate controllers for each service.
Utilise the application context and extract beans from there.
As described in Get bean from ApplicationContext by qualifier, you could add qualifiers to each service implementations and have something like this in the myControllerFunc:
BeanFactoryAnnotationUtils.qualifiedBeanOfType(ctx.getBeanFactory(), MyServiceInterface.class, source)

The bean could not be injected as a 'Type' because it is a JDK dynamic proxy that implements: reactor.fn.Consumer

My Spring 4 application, which uses Reactor 2, fails to start with:
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'orderHandlerConsumer' could not be injected as a 'fm.data.repository.OrderHandlerConsumer' because it is a JDK dynamic proxy that implements:
reactor.fn.Consumer
Action:
Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on #EnableAsync and/or #EnableCaching.
The OrderHandlerConsumer is really simple:
#Service
#Order(Ordered.HIGHEST_PRECEDENCE)
public class OrderHandlerConsumer implements Consumer<Event<OrderEnvelope>> {
#Override
public void accept(Event<OrderEnvelope> event) {
event.getData().getLatch().countDown();
}
}
Any ideas what might be going awry?
In your application class file where you define it as Spring application, add underneath it.
#SpringBootApplication
#EnableCaching(proxyTargetClass = true)
While the accepted answer will solve this issue, I think it will be more appropriate for me to explain why appling proxyTargetClass = true will fix this.
First of all, Spring, as a framework, utilizes proxing in order to supply the bean with some extended functionality, such as declaritive transactions via #Transactional, or caching by the means of #Cacheable and e.t.c. There are, in general, 2 ways(*) Spring can create proxy on top of your bean:
Jdk dynamic proxing
CGLib proxing
Offical documentation on this, in case you are interested.
Spring can create jdk dynamic proxy of the bean (in case proxing is required for this bean of course) if original class of the bean implements at least one interface. So spring basically create another implementation of this interface at runtime with some additional logic on top of original class.
What is the problem: if the bean is proxied by the means of jdk dynamic proxing , then you cannot inject this bean via its original class. So something like this:
#SpringBootApplication
#EnableTransactionManagement(proxyTargetClass = false)
public class StackoverflowApplication {
#Autowired private SomeService service;
public static void main(String[] args) {
SpringApplication.run(StackoverflowApplication.class, args);
}
}
#Service
class SomeService implements SomeInterface {
#Override
#Transactional
public void handle() { }
}
interface SomeInterface {
void handle();
}
wont work. Why? Well, becuase #Transactional tells Spring that it needs to create proxy of SomeService at runtime, and within #EnableTransactionManagement I specifically asked Spring to make it by the means of jdk dynamic proxy - spring will succeed, since jdk dynamic proxy can be created, but the problem is at runtime there is not bean of type SomeService, there is only a bean of type SomeInterface (by the way, if you inject service here not by the class, but by the interface - it will work, I assume you understand the reason by reading explaination above).
Solution: by applying #EnableTransactionManagement(proxyTargetClass = true) (notice true value here) you force spring to create CGlib proxy (this rule is applicable only for beans that utilize declarative transaction management, i.e. via annotations). In case of CgLib proxing, Spring will try to extend the original class, and add additional functionality at runtime in the generated child class. And in this case injection by class will work - because the bean extends class SomeService, so
#Autowired
private SomeService someService;
will work perfectly fine. But, in general, if possible, inject bean by interface, not by class. In this case both Cglib and jdk dynamic proxy will work. So, be aware of proxing mechanisms spring can use. Hope it helped, have a nice day.
You can assign a bean name to your OrderHandlerConsumer class so that Autowire resolution will be easier, Moreover, Instead of Autowiring with the concrete class, try to auto-wire with the interface. So that you can change #Service annotation to,
#Service(value="orderHandlerConsumer")
and try to Autowire with the interface type,
#Autowire
reactor.fn.Consumer orderHandlerConsumer;
Please try autowiring as below
class Test{
#Autowired
private Consumer orderHandlerConsumer;
}
If the target object to be proxied implements at least one interface
then a JDK dynamic proxy will be used. All of the interfaces
implemented by the target type will be proxied. If the target object
does not implement any interfaces then a CGLIB proxy will be created.
https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch08s06.html
You can call it two ways.
1st way is without mentioning the proxy [with default proxy], you can Autowire it by the interface like below.
#Autowired
private Consumer orderHandlerConsumer;
Spring AOP will create an instance for OrderHandlerConsumer.
2nd way is, mention the proxy in the bean as ScopedProxyMode.TARGET_CLASS.
then you can Autowire an instance without the interface [based on the class].
#Service
#Order(Ordered.HIGHEST_PRECEDENCE)
#Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class OrderHandlerConsumer implements Consumer<Event<OrderEnvelope>> {
#Override
public void accept(Event<OrderEnvelope> event) {
event.getData().getLatch().countDown();
}
}
and Autowire by the class like below.
#Autowired
private OrderHandlerConsumer orderHandlerConsumer;

Define bean using factory method in plain Java EE - WITHOUT Spring

I want to create a bean which can be automatically injected (autowired) by plain Java EE, not with Spring.
The code I have is this:
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
#ApplicationScoped
public class MyConnector {
....
private Client client = ClientBuilder.newClient();
....
}
I'd like to use dependency injection like that instead:
#Inject
private Client client;
In good old Spring I would just define the bean following the guideline http://docs.spring.io/spring/docs/3.1.0.M1/spring-framework-reference/html/beans.html#beans-factory-class-static-factory-method
<bean id="client"
class="javax.ws.rs.client.ClientBuilder"
factory-method="createInstance"/>
and the #Autowired would inject the proper bean.
QUESTION: Can I achieve the same somehow in the plain Java EE without Spring? Can I define a bean in a similar way - and if so, where (in which configuration file)?
You may write your own CDI producer for this purpose
#Dependent public ClientFactory{
#Produces Client createClient() {
return ClientBuilder.newClient();
}
}
Now you are able to use CDI's #Inject to get an instance within your Bean
#ApplicationScoped public class MyConnector {
#Inject private Client client;
}
With those kind of producers, CDI provides an easy-to-use implementation of the factory pattern. You are able to inject nearly everything and everywhere, not only Classes but also Interfaces, other JEE ressources and even primitive types. The injection point do not have to be a class member, but may also be e.g. an argument in a method ...
Each injection will give you a different Proxy, so you are able to inject even more than one Client to your Bean if you have to. If those Proxy objects refer to the same instances or not depends on your implementation of the factory method, but usually you do not want this.

#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:";
}
}

Web Service Client in a Stateless Enterprise Bean

What is the correct way to implement a stateless EJB 3.1 for invoking a web service. My client works as a Servlet, but I want to move the invocation into a EEJ bean. I have to add username and password in the SOAP header envelop to access the WS, which is working fine.
The service the the servlet is using looks like this;
#WebServiceClient(name = "MessageService", targetNamespace = "http://...", wsdlLocation = "...wsdl")
public class MessageService
extends Service
Can I wrap MessageService in a Stateless EJB or should the bean itself use #WebServiceRef (as in the tutorial) without wrapping the MessageService ?
Tutorial
Local Service
If the client and the provider lives in same EAR or WAR on the application server, can be invoked like a ordinal EJB. e.g.
#WebService
#Stateless
public class CalculatorBean implements Calculator {
public int add(int a, int b) {
return a + b;
}
}
The CalculatorBean is threadsafe. All business logic that occurs within the add method
is part of a container-managed transaction and not participate in any global transaction.
Alternatively, the client code can look up in the JNDI namespace.
Remote Service
The runtime can inject a service object or a port object into a member variable annotated with javax.xml.ws.WebServiceRef.
#WebServiceRef(CalculatorService.class)
private Calculator port;
The CalculatorService class is annotated with the javax.xml.ws.WebServiceClient annotation (the client of the service), which has a wsdlLocation attribute.
If you want to wrap the WebService into the EJB, see this answer. For read a discussion about this, see EJB and Web Services: getting the best of both worlds.

Categories