I want to call my Spring bean from my EJB Session Bean. Here is an example scenario that I want to achieve.
Spring Interface:
public interface ReqSpring {
public String processMsg(String msg);
}
Spring Bean:
#Component
public class ReqStringImpl implements ReqSpring{
public String processMsg(String msg) {
return "Msg ["+msg+"] is processed";
}
}
EJB Interface:
#Remote
public interface EjbService{
String echo(String msg);
}
EJB Session Bean:
(please notice that I have used #Autowired over a Spring object)
#Stateless(name = "EjbWS", mappedName = "EjbWS")
#WebService(name = "EjbService", portName = "EjbServicePort")
public class EjbServiceBean implements EjbService {
=====> #Autowired
=====> private ReqSpring reqSpring;
public EjbServiceBean() {
}
#WebMethod
public String echo(#WebParam(name="msg")String msg) {
// This is printing null
System.out.println("ReqSpring = "+reqSpring);
return reqSpring.processMsg(msg);
}
}
My Application failed to load the ReqSpring object from my EJB and always generating NullPointerException. Any idea why this is happening?
You can't inject a Spring Bean into a EJB like that because the EJB is not managed by the Spring container. Anyway, by using the SpringBeanAutowiringInterceptor, you will be able to do it. Try with this annotation :
#Stateless(name = "EjbWS", mappedName = "EjbWS")
#WebService(name = "EjbService", portName = "EjbServicePort")
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class EjbServiceBean implements EjbService {
#Autowired
private ReqSpring reqSpring;
public EjbServiceBean() {
}
#WebMethod
public String echo(#WebParam(name="msg")String msg) {
System.out.println("ReqSpring = "+reqSpring);
return reqSpring.processMsg(msg);
}
}
Related
I need to intercept methods from a interface, and found this implementation of MethodInterceptor, which I tested on a new spring app and worked.
The problem is, I can't seem to get it working on the spring application I need it to.
#Configuration
public class TestMethodConfig {
#Autowired
private TestService testService;
#Bean
#Primary
public ProxyFactoryBean testProxyFactoryBean() {
ProxyFactoryBean testProxyFactoryBean = new ProxyFactoryBean();
testProxyFactoryBean.setTarget(testService);
testProxyFactoryBean.setInterceptorNames("testMethodInterceptor");
return testProxyFactoryBean;
}
}
#Service
public class TestServiceImpl implements TestService{
#Override
public void testMethod(String test) {
System.out.println("testService String");
}
}
public interface TestService{
void testMethod(String test);
}
#RestController
public class Controller {
#Autowired
private TestService testProxyFactoryBean;
#GetMapping(value = "/test")
public void test(){
testProxyFactoryBean.testMethod("valor");
}
}
#Component
public class TestMethodInterceptor implements MethodInterceptor {
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before method");
System.out.println("invocation: " + Arrays.toString(invocation.getArguments()));
Object retVal = invocation.proceed();
System.out.println("after method");
return retVal;
}
}
I used Spring Actuator to check the beans relations, and I found that the #Autowired TestService on Controller should be getting assigned to testProxyFactoryBean, but its getting assigned to the TestServiceImpl bean instead, so I believe there is a problem creating the proxy.
In short
I don't know how/why it was:
on a new spring app and worked.
but:
I can't seem to get it working on the spring application I need it to.
..can probably be fixed!
Make it consistent
Or:
#Configuration
public class TestMethodConfig {
#Autowired
private TestService testService;
}
...
// !!
public class TestServiceImpl implements TestService{
#Override
public void testMethod(String test) {
System.out.println("testService String");
}
}
...
#Service // !!!
public interface TestService{
void testMethod(String test);
}
...
#RestController
public class Controller {
#Autowired
private TestService testProxyFactoryBean;
...
Or: Impl!
(Use Interface and Impl consistently!)
In Detail
6.4. Using the ProxyFactoryBean to Create AOP Proxies
esp. Proxying Interfaces.
So with "least impact" (and java config), it should be:
#Configuration
public class TestMethodConfig {
// !!! Impl from component-scan (#Service), NOT interface:
#Autowired
private TestServiceImpl testServiceImpl; // or define custom, or "inline"...
#Bean
#Primary // only if you need it, better would be: distinct!
public ProxyFactoryBean testProxyFactoryBean() {
ProxyFactoryBean testProxyFactoryBean = new ProxyFactoryBean();
// !!! set proxyInterface as documented:
testProxyFactoryBean.setProxyInterface(TestService.class);
testProxyFactoryBean.setTarget(testServiceImpl);
testProxyFactoryBean.setInterceptorNames("testMethodInterceptor");
// ...
return testProxyFactoryBean;
}
}
..enjoy! ;)
Does anyone know if I should be able to use property placeholder as an expression in a Qualifier? I can't seem to get this working.
I am using spring 3.0.4.
#Controller
public class MyController {
#Autowired
#Qualifier("${service.class}")
Service service;
}
#Service
#Qualifier("ServiceA")
ServiceA implements Service {
public void print() {
System.out.println("printing ServiceA.print()");
}
}
#Service
#Qualifier("ServiceB")
ServiceB implements Service {
public void print() {
System.out.println("printing ServiceB.print()");
}
}
XML:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="file:/etc/config.properties"/>
</bean>
config.properties:
config.properties
service.class=serviceB
This works. You can leave off the service names if you just use the default spring bean name. serviceA vs ServiceA, etc.
#Controller
class MyController {
#Autowired(required=false)
#Qualifier("Service")
Service service;
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("app-ctx.xml", MyController.class);
for(String s:context.getBeanDefinitionNames()){
System.out.println(s);
for(String t:context.getAliases(s)){
System.out.println("\t" + t);
}
}
context.getBean(MyController.class).service.print();
}
}
public interface Service {
void print();
}
#Service(value="ServiceA")
public class ServiceA implements example.Service {
public void print() {
System.out.println("printing ServiceA.print()");
}
}
#Service(value="ServiceB")
public class ServiceB implements example.Service {
public void print() {
System.out.println("printing ServiceB.print()");
}
}
XML:
<beans>
<alias name="${service.class}" alias="Service"/>
<context:property-placeholder location="example/app.properties"/>
<context:component-scan base-package="example"/>
<beans>
Props:
service.class=ServiceB
This solution works without XML and with properties file.
Yours classes improved:
MyController.java:
#Controller
public class MyController {
#Autowired
public MyController(#Qualifier("MyServiceAlias") MyService myService) {
myService.print();
}
}
ServiceA.java:
#Service("serviceA")
public class ServiceA implements MyService {
#Override
public void print() {
System.out.println("printing ServiceA.print()");
}
}
ServiceB.java:
#Service("serviceB")
public class ServiceB implements MyService {
#Override
public void print() {
System.out.println("printing ServiceB.print()");
}
}
application.properties (here you can change which class will be loaded):
service.class=serviceA
And important configuration file AppConfig.java:
#Configuration
public class AppConfig {
#Autowired
private ApplicationContext context;
#Bean
public MyService MyServiceAlias(#Value("${service.class}") String qualifier) {
return (MyService) context.getBean(qualifier);
}
}
Additional explanations:
Use #Qualifier only for field which will be autowired. For services, to specify bean name, use #Service.
If you want standard bean name you don't need to use #Service with specyify name. For example, standard bean name for ServiceA is serviceA (not ServiceA - see big first letter), so #Service("serviceA") redundant (#Service is enough).
I based AppConfig on this answer: Spring Bean Alias in JavaConfig.
This solution is better than this Spring Qualifier and property placeholder, because you don't need XML.
Tested on Spring Boot 1.5.7.
I would venture to guess the answer is no, just based on the write ups in a few javadoc pages. For example, see the docs for #Value:
http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/beans/factory/annotation/Value.html
Notice they make special mention of using expressions in the annotation. For comparison, the docs for #Qualifier:
http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/beans/factory/annotation/Qualifier.html
Which make no mention of expressions. Obviously not a definitive answer (but spring is generally very good on documentation). Also, if expressions were supported in the #Qualifier annotation I would expect they work the same way as the #Value annotation (just based on spring being a very consistent framework).
Spring 3.1 has the new profile bean feature, which seems like it can accomplish something like what you're trying to do. Here's a write up for that:
http://blog.springsource.com/2011/02/14/spring-3-1-m1-introducing-profile/
As a workarround, you can set the desired Spring service implementation based on its name in your config.properties.
#Controller
public class MyController {
//add a String which will hold the name of the service to implement
#Value("${service.class}")
private String serviceToImplement;
Service service;
// now autowire spring service bean based on int name using setter
#Autowired
public void setService(ApplicationContext context) {
service = (Service) context.getBean(serviceToImplement);
}
}
#Service
#Qualifier("ServiceA")
ServiceA implements Service {
public void print() {
System.out.println("printing ServiceA.print()");
}
}
#Service
#Qualifier("ServiceB")
ServiceB implements Service {
public void print() {
System.out.println("printing ServiceB.print()");
}
}
config.properties
service.class=serviceB
Maybe give this a whirl:
#Controller
public class MyController {
private String serviceId;
#Value("${serviceId}")
public void setServiceId(String serviceId) {
this.serviceId = serviceId;
}
#Autowired
#Qualifier(serviceId)
Service service;
}
I have an interface(X) with a method which prints out a statement and the interface has 2 implementations of it X1 and X2 and there is this class Y which has 2 objects of X autowired by type for X1 and X2 with the interface. i.e, like private X x; and private X x2; and when I call x.statement() it prints the default profile statement but when x2.statement() is called it still prints the x.statement() print statement instead of x2.statement().
BTW I am using Spring boot.
public interface HelloWorldService {
public String getGreeting();
}
#Component
#Profile({ "default", "english" })
public class HelloWorldServiceEnglishImpl implements HelloWorldService {
#Override
public String getGreeting() {
return "Hello World";
}
}
#Component
#Profile("spanish")
public class HelloWorldServiceSpanishImpl implements HelloWorldService {
#Override
public String getGreeting() {
return "Hola Mundo";
}
}
-
#Controller
public class GreetingController {
#Autowired
private HelloWorldService helloWorldService;
#Autowired
private HelloWorldService helloWorldServiceSpanish;
public void setHelloWorldServiceSpanish(HelloWorldServiceSpanishImpl helloWorldServiceSpanish) {
this.helloWorldServiceSpanish = helloWorldServiceSpanish;
}
public void setHelloWorldService(HelloWorldService helloWorldService) {
this.helloWorldService = helloWorldService;
}
public String sayHello() {
String greeting = helloWorldService.getGreeting();
System.out.println(helloWorldServiceSpanish.getGreeting());
System.out.println(greeting);
return greeting;
}
}
Firstly, what makes you think one of the Injected beans will be the 'English' bean and one will be the 'Spanish' bean. You inject two instances of the bean defined by the active profile: the 'English' bean. There is no Bean HelloWorldServiceKannadaImpl active for this profile. So both instances are instances of HelloWorldServiceEnglishImpl.
//this code is not called. The instance variable is auto-wired by field
//and the auto-wired bean is the only one available: the English one.
public void setHelloWorldServiceSpanish(HelloWorldServiceSpanishImpl helloWorldServiceSpanish) {
this.helloWorldServiceSpanish = helloWorldServiceSpanish;
}
How it should be:
#Controller
public class GreetingController {
//will be English or Spanish depending on Active profile.
#Autowired
private HelloWorldService helloWorldService;
public void sayHello() {
String greeting = helloWorldService.getGreeting();
System.out.println(greeting);
}
}
In your original code either remove the #Profile from the two beans, or change to spring.profiles.active=english,spanish and it might work as you expect. Although having both kinds of defeats the whole purpose which is to have dynamically injected bean based on the runtime environment.
At a time, only one Profile will be ACTIVE depending upon the set value, so you either can be able to print English or Spanish, but NOT both as per your config.
You can look at here for more details.
If you want to be able to inject the two beans of the same type at the same time you shouldn't bind them to profiles: you can assign them different names.
#Component("english")
public class HelloWorldServiceEnglishImpl implements HelloWorldService {
#Override
public String getGreeting() {
return "Hello World";
}
}
#Component("spanish")
public class HelloWorldServiceSpanishImpl implements HelloWorldService {
#Override
public String getGreeting() {
return "Hola Mundo";
}
}
then you can inject them with the #Named (java api) or #Qualifier (spring api) (if I remember it correctly) annotation
#Named("english") // #Qualifier("english")
#Autowired
private HelloWorldService helloWorldService;
#Named("spanish") // #Qualifier("spanish")
#Autowired
private HelloWorldService helloWorldServiceSpanish;
I have a simple POJO class called MyService.java:
#RequestScoped
public class MyService {
public String helloWorld(){
return "hello world!";
}
}
I have a JAX-RS class where I want to Inject my POJO using CDI:
#Path("service")
public class RestfulService {
public static AtomicInteger counter = new AtomicInteger(0);
#EJB
MyEJB ejb;// The EJb injection works!
#Inject
MyService service; // CDI injection does NOT work!
#GET
#Path("counter")
#Produces(MediaType.TEXT_PLAIN)
public String getTotal() {
return "Number of hits: " + counter.incrementAndGet();
}
}
Here is the exception thrown:
g.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=MyService,parent=RestfulService,qualifiers={},position=-1,optional=false,self=false,unqualified=null,1492861225)
at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74)
The files beans.xmlis present and the discovery-mode is set to annotated.
Any help please? Seems a basic example to me.
I've just started using Guice and having trouble with understanding the guice way of injection. I'm very familiar with Spring, but this seems a bit different.
I have a DAO class:
public class SomeDAO {
#NotNull
private DB db = null;
public SomeDAO (String databaseName) throws Exception{
xxxxxxxxxxxxxxxxxxxxxxxx
}
}
I have a controller, say:
public class SomeController {
private SomeDAO someDAO;
}
How should i use guice here to inject someDAO object? Note that the databaseName in SomeDAO constructor should be provided from SomeController.
Thanks.
Ideally SomeController shouldn't have to know the name of the database. This would come from a configuration file or from your application context and you'd inject your DAO like this:
public class SomeController {
private final SomeDAO someDAO;
#Inject
SomeController(SomeDAO someDAO) {
this.someDAO = someDAO;
}
}
And then to inject the database name you could do something like this:
public class SomeDAO {
#NotNull
private DB db = null;
#Inject
public SomeDAO (#IndicatesDatabaseName String databaseName) throws Exception {
...
}
}
In this case Guice will provide databaseName (see https://code.google.com/p/google-guice/wiki/BindingAnnotations). If you want to give the controller knowledge of the database name then you could consider just newing the DAO from the controller (but still injecting the controller) or using assisted inject.
EDIT:
If the controller really needs to know about the database you could use assisted inject:
public class SomeController {
private final SomeDAO someDAO;
#Inject
SomeController(#Assisted String databaseName) {
this.someDAO = new SomeDAO(databaseName);
}
}
public interface ControllerFactory {
public SomeController create(String databaseName);
}
public static class MyModule extends AbstractModule {
#Override
protected void configure() {
install(new FactoryModuleBuilder()
.implement(SomeController.class, SomeController.class)
.build(ControllerFactory.class));
}
}
And then inject ControllerFactory where SomeController is needed. You could apply the same assisted injection to SomeDAO if it ends up needing more injected dependencies, as well.