First, the problem is when I invoke the ejb from the rest servlet, the ejb is always null.
I have a rest web service developed in jersey + spring 3.0.5. And an EJB 3.1 for services.
I have package the war and jar in an ear so my application looks like (I'm using maven for dependency):
+ear
++war
++jar
I was wondering how I could call the services in the jar file from my classes in the war file. As far as I remember it's through JNDI and I need to expose the ejb apis? How should I do that?
I'm sure the EJB are created successfully because I can see the log in the server like this:
Portable JNDI names for EJB UserServiceBean :
[java:global/demo-cg-ear-0.0.1-SNAPSHOT/demo-cg-ejbs/UserServiceBean!com.demo.cg.service.user.UserServiceBeanLocal,
java:global/demo-cg-ear-0.0.1-SNAPSHOT/demo-cg-ejbs/UserServiceBean]|#]
But the problem is when I invoke it in the rest jersey servlet, it's always null:
#Path("/payment")
#Stateless
public class PaymentService {
#Path("/payment")
#Stateless
public class PaymentService {
#EJB
private UserServiceBeanLocal userServiceBean;
#GET
#Path("/hello")
public Response savePayment() {
String result = userServiceBean.getName();
return Response.status(200).entity(result).build();
/* return Response.status(200).entity("hello edward").build(); */
}
}
My applicationContext.xml file
<context:annotation-config />
<context:component-scan base-package="com.sido" />
<context:property-placeholder location="WEB-INF/build.properties" />
<!-- <bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
<property name="alwaysUseJndiLookup" value="true" /> </bean> -->
<jee:jndi-lookup id="userServiceBean"
jndi-name="java:global/sido-cg-ear-0.0.1-SNAPSHOT/sido-cg-ejbs/UserServiceBean"
resource-ref="true" lookup-on-startup="true"
expected-type="com.sido.cg.service.user.UserServiceBeanLocal"
proxy-interface="com.sido.cg.service.user.UserServiceBeanLocal"></jee:jndi-lookup>
UserBean class
#Interceptors(SpringBeanAutowiringInterceptor.class)
#Stateless
public class UserServiceBean implements UserServiceBeanLocal {
private String name;
public UserServiceBean() {
name = "edward";
}
#PostConstruct
private void init() {
name = "edward";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Thanks,
czetsuya
For those who are interested this is how I did it: http://czetsuya-tech.blogspot.com/2012/05/how-to-call-stateless-ejb-from-spring.html
Related
I have a project which uses an old spring.jar (1.2.6),from this project, I am expected to call a newer version (spring version 5.0.7) spring boot project's method. Below is the way I am creating my bean in old version project.
I am getting NullPointer exception while creating the Autowired bean.
Create bean from XML:spring
test-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "qvc-spring-beans.dtd">
<beans>
<bean name="testPci" class="com.test.client.TestPci">
</bean>
</beans>
sampleParent-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans SYSTEM "spring-beans.dtd">
<beans>
<import resource="classpath:/com/test/test-context.xml" />
<bean id="classA" class="com.test.A" >
<property name="testPci">
<ref bean="testPci"/>
</property>
</bean>
</beans>
Java code old spring project:
package com.test;
public class A{
private TestPci testPci;
private ApplicationContext ctx;
public TestPci getTestService() {
if (!StringUtils.isValid(ctx)) {
ctx = new ClassPathXmlApplicationContext("./com/test/test-context.xml");
}
if (!StringUtils.isValid(this.testPci)) {
if (StringUtils.isValid(ctx)) {
testPci = (TestPci) ctx.getBean("testPci");
TestPci testPci = (TestPci) ctx
.getBean("testPci");
this.setSecureTestService(testPci);
}
}
return this.getSecureTestService();
}
public TestPci getSecureTestService() {
return testPci;
}
public void setSecureTestService(TestPci testPci) {
this.testPci = testPci;
}
public void methodA(){
//Calling newer code form old spring code:
testPci.testing("1", "2", "3");
}
}
Calling "TestPci" class as above, but when trying to call using the above, it actually calls the "TestPci"."testing" method. But the object autowired as "testWebClientService" is returning as null. I would like to get the object created instead it returns null.
New spring version class:
#Service
#EnableConfigurationProperties(TestWebClientProperties.class)
#Configurable
public class TestPci{
#Autowired
private TestWebClientService testWebClientService;
public Map<String, String> testing(String a, String b, String c) throws Exception {
Map<String, String> map = testWebClientService.find(a, b, c);
System.out.println("**=="+map.get(0));
return map;
}
}
Adding junit which is used to call the TestPci class from newer version of spring:
#RunWith(SpringJUnit4ClassRunner.class)
#EnableConfigurationProperties(TestWebClientProperties.class)
#SpringBootTest(classes = { TestWebClientService.class, TestPci.class }, webEnvironment = WebEnvironment.NONE)
public class TestJunit {
#MockBean(name="restTemplate")
public RestTemplate restTemplate;
#Autowired
private TestPci testPci;
#Test
public void ff() throws Exception {
testPci.testing("1","1","1");
}
}
I have the following situation:
#Controller
public class myController {
#Autowired
private IProxy service;
public ModelAndView init(HttpServletRequest request, HttpServletResponse response) throws Exception {
List<String> list = service.getName();
}
}
Then my Service is define as follow:
public interface IProxy {
public List<String> getName();
}
Proxy class is responsible for the lookup to the remote bean
#Service("service")
public class Proxy implements IProxy {
...
public List<String> getName() {
return myClass.getName();
}
And the implementation is the following:
#Interceptors(interceptor.class)
#Stateless
#Resource(name = "java:/db")
#Remote(MyClassRemote.class)
public class MyClassImpl extends MyEjb implements MyClassRemote{
#PersistenceContext(unitName = "db")
private EntityManager em;
#Resource
private SessionContext sctx;
#Autowired
public IMyRepo myRepo;
#Override
public List<String> getName() {
try {
return myRepo.getName(em);
}
catch (Exception ex) {
ex.printStackTrace();
throw ex;
}
finally {}
}
So, the problem is that here myRepo is null. I don't know why because IMyRepo and his implementation are always located within the path scanned by Spring.
Just one clarification: MyRepo class that implements IMyRepo is annotated with #Repository.
Any idea?
you can inject spring beans in EJB using Spring interceptors, as explained here in the official documentation. Basically you'll need to adjust your class as follows:
// added the SpringBeanAutowiringInterceptor class
#Interceptors({ interceptor.class, SpringBeanAutowiringInterceptor.class })
#Stateless
#Resource(name = "java:/db")
#Remote(MyClassRemote.class)
public class MyClassImpl extends MyEjb implements MyClassRemote{
// your code
}
You'll also need to define the context location in a beanRefContext.xml file (with your own application context file):
application-context.xml version
<bean id="context"
class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg>
<list>
<value>application-context.xml</value>
</list>
</constructor-arg>
</bean>
Java Configuration version:
<bean id="context"
class="org.springframework.context.annotation.AnnotationConfigApplicationContext">
<constructor-arg>
<list>
<value type="java.lang.Class">com.your.app.Configuration</value>
</list>
</constructor-arg>
</bean>
Spring beans and EJB are two different things, you can't just inject a Spring bean in an EJB, because that EJB is no Spring bean, so Spring doesn't know there is a field which should be injected by Spring (unless you use some fancy AOP stuff, which can enable injection into non-Spring-managed beans).
I have written a custom authenticator for my Play 2.3.4 application which has spring dependency injection configured. I want to be able to inject an 'authService' into my authenticator, but this is not working. My authService is always null. Is it possible to configure autowired injection into authenticators? My authenticator is as follows:
package controllers;
#org.springframework.stereotype.Component
public class AppAuthenticator extends Security.Authenticator {
#Autowired
#Qualifier("authService")
private AuthService authService;
#Override
public String getUsername(Context ctx) {
...
authService.getAuthenticatedUser();
...
}
public void setAuthService(AuthService authService) {
this.authService = authService;
}
...
}
And my Spring configuration includes:
<context:component-scan base-package="controllers"/>
<bean id="authService" class="com.my.auth.class.AuthServiceClass" />
<bean class="play.mvc.Security$AuthenticatedAction" scope="prototype" />
In summary, spring doesn't seem to be injecting properties into my Sercuirty.Authenticator. How do you configure this correctly?
Where is a good place to store custom config info in spring mvc 3.x and how would I access that info globally via any controller?
Is there a built in config manager?
I assume 'custom config' means a configuration file the code reads / you / your operations team can update?
One easy solution is to use spring beans xml configuration file and deploy your war in exploded fashion.
Create a configuration java class:
// File: MyConfig.java ------------------------------------
public class MyConfig {
private String supportEmail;
private String websiteName;
// getters & setters..
}
Configure the class as a Spring bean and set its properties on your spring beans xml file (can also create a new file and use <import resource="..."/>):
// File: root-context.xml ----------------------------------------
<beans ...>
...
<bean class="com.mycompany.MyConfig">
<property name="supportEmail" value="support#mycompany.com"/>
<property name="websiteName" value="Hello Site"/>
</bean>
...
</beans>
Inject your configuration class (eg: in a controller)
// File: HelloController.java ------------------------------------
#Controller
#RequestMapping("/hello")
public class HelloController {
#Autowired MyConfig config;
// ...
}
However updates to the configuration would require re-deploy / server restarts
You can also use <context:property-placeholder>.
It looks like this.
myapp.properties:
foo=bar
spring beans xml:
<context:property-placeholder location="classpath:myapp.properties"/>
Or
<context:property-placeholder location="file:///path/to/myapp.properties"/>
Controller:
import org.springframework.beans.factory.annotation.Value;
...
#Controller
public class Controller {
#Value("${foo}")
private String foo;
If you want to get properties programmatically, you can use Environment with #PropertySource.
Configuration:
#Configuration
#PropertySource("classpath:myapp.properties")
public class AppConfig {
#Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Controller:
#Controller
public class Controller {
#Value("${foo}")
private String foo;
#Autowired
private Environment env;
#RequestMapping(value = "dosomething")
public String doSomething() {
env.getProperty("foo");
...
}
Hope this helps.
How can we switch between different Implementations in Spring Context XML with an Boolean?
for example:
<bean id="detailsController" class="com.something.detailsController" >
if true then
<property name="dao" ref="firstDao"/>
else
<property name="dao" ref="secoundDao"/>
I know in Spring3 we can work with profiles
You could do that by modifying your Java code and use Spring EL together with ApplicationAware and InitializingBean.
public class DetailsController implements ApplicationContextAware, InitializingBean {
private DetailsControllerDAO dao;
private String daoName;
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void afterPropertiesSet() {
dao = applicationContext.getBean(daoName);
}
public void setDaoName(String daoName) {
this.daoName = daoName;
}
}
In XML:
<bean id="detailsController" class="com.something.detailsController">
<property name="daoName" value="#{myCondition ? 'firstDao' : 'secondDao'}" />
</bean>
Of course, this solution has the disadvantage to add dependency to Spring code in your controller. To avoid that, you could move that code in a proxy class, as described by Guillaume Darmont.
I dont think this can be done at the XML level.
Spring really cannot do that. See the bean lifecycle. Been classes are created, than properties are injected and than afterPropertiesSet() or #PostConstructor methods are invoked. Of course when I omit lazy initialized beans.
But if you want for testing etc. and so you need just the firstDao or the secondDao in your application at the sametime that depends just on your settings, you can use a bean factory. The bean factory creates your bean as you want. I also use it for to split development environment, test environment and production environment.
package com.dummyexample.config;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Factory bean to create real or test dao.
* The result depends on realDaoEnabled configuration parameter.
*
* #author Martin Strejc
*/
#Configuration
public class DaoBeanFactory {
// mapping to servlet context configuration
#Resource(mappedName = "realDaoEnabled")
private Boolean realDaoEnabled = true;
// TestDao extends or implements Dao
#Autowired
private TestDao testDao;
// ProdDao extends or implements Dao
#Autowired
private ProdDao prodDao;
public DaoBeanFactory() {
}
#Bean(name="dao")
public Dao getDao() {
if(realDaoEnabled) {
return prodDao;
}
return testDao;
}
}
Since your DAOs are exchangeable, they inherits the same type (abstract class or interface). Thus you can write a RoutingDetailsControllerDAO.
Let's say that your common interface is named DetailsControllerDAO, with two methods getDetails and getMoreDetails inside, the code would be :
public class RoutingDetailsControllerDAO implements DetailsControllerDAO {
private DetailsControllerDAO firstDAO;
private DetailsControllerDAO secondDAO;
protected DetailsControllerDAO getDAOToUse() {
return YOUR_BOOLEAN_CONDITION ? firstDAO : secondDAO;
}
#Override
public Details getDetails() {
return getDAOToUse().getDetails();
}
#Override
public Details getMoreDetails() {
return getDAOToUse().getMoreDetails();
}
// Insert firstDAO and secondDAO setters below
...
}
Your Spring XML config is now :
<bean id="detailsController" class="com.something.detailsController" >
<property name="dao" ref="routingDetailsControllerDAO"/>
</bean>
<bean id="routingDetailsControllerDAO" class="com.something.RoutingDetailsControllerDAO">
<property name="firstDao" ref="firstDao"/>
<property name="secondDao" ref="secondDao"/>
</bean>
Few possibilities:
You can either use profiles (<beans profiles="profileOne">).
You can use FactoryBean to create the correct DAO
You can use SPeL
The last one is the easiest:
<bean id="detailsController" class="com.something.detailsController">
<property name="dao" ref="#{condition ? 'firstDao' : 'secondDao'}" />
</bean>
Of course you can load bean name from properties file via property configurer:
<bean id="detailsController" class="com.something.detailsController">
<property name="dao" ref="${bean.name.from.properties.file}" />
</bean>