I am quite new to Spring and Activiti. I'm developing annotation based Spring web application with embedded Activiti engine. I have some services implemented, SubscriptionService is one of them. In one process I call that service as bean with:
activiti:expression="${subscriptionService.getContacts(publisherCode, contactType)}"
Service:
#Service
#Transactional
public class DBSubscriptionService implements SubscriptionService {
...
}
I have separated test module and web module. Test module loads context from activiti.cfg.xml with
#ContextConfiguration("classpath:activiti.cfg.xml")
and it is:
<bean id="processEngineConfiguration"
class="org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
<property name="databaseType" value="h2" />
<property name="databaseSchemaUpdate" value="true" />
<property name="jobExecutorActivate" value="false" />
<property name="history" value="full" />
<property name="mailServerPort" value="2025" />
</bean>
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>
<bean id="repositoryService" factory-bean="processEngine"
factory-method="getRepositoryService" />
<bean id="runtimeService" factory-bean="processEngine"
factory-method="getRuntimeService" />
<bean id="taskService" factory-bean="processEngine"
factory-method="getTaskService" />
<bean id="historyService" factory-bean="processEngine"
factory-method="getHistoryService" />
<bean id="managementService" factory-bean="processEngine"
factory-method="getManagementService" />
<bean id="identityService" factory-bean="processEngine"
factory-method="getIdentityService" />
<bean id="formService" factory-bean="processEngine"
factory-method="getFormService" />
<context:component-scan base-package="cz.muni.fi.cep" />
<context:annotation-config />
In test module, everything works fine. But in web module when it should call subscriptionService Bean it throws:
Unknown property used in expression: ${subscriptionService.getContacts(publisherCode, contactType)}
Caused by: org.activiti.engine.impl.javax.el.PropertyNotFoundException: Cannot resolve identifier 'subscriptionService'
at org.activiti.engine.impl.juel.AstIdentifier.eval(AstIdentifier.java:83)
at org.activiti.engine.impl.juel.AstMethod.invoke(AstMethod.java:79)
at org.activiti.engine.impl.juel.AstMethod.eval(AstMethod.java:75)
at org.activiti.engine.impl.juel.AstEval.eval(AstEval.java:50)
at org.activiti.engine.impl.juel.AstNode.getValue(AstNode.java:26)
at org.activiti.engine.impl.juel.TreeValueExpression.getValue(TreeValueExpression.java:114)
at org.activiti.engine.impl.delegate.ExpressionGetInvocation.invoke(ExpressionGetInvocation.java:33)
at org.activiti.engine.impl.delegate.DelegateInvocation.proceed(DelegateInvocation.java:37)
at org.activiti.engine.impl.delegate.DefaultDelegateInterceptor.handleInvocation(DefaultDelegateInterceptor.java:25)
at org.activiti.engine.impl.el.JuelExpression.getValue(JuelExpression.java:48)
... 363 more
So I understand problem is that Process engine does not use right application context, because subscription service is autowired to other classes just fine. But I don't know how to fix it.
Web module is purely annotation based:
#EnableAutoConfiguration
#Configuration
#EntityScan(basePackages = "cz.muni.fi.cep")
#ComponentScan(basePackages = "cz.muni.fi.cep")
public class App extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
...
}
And Activiti configuration:
#Configuration
public class ActivitiConfig {
#Bean
public ProcessEngine processEngine(ProcessEngineConfigurationImpl pec, ApplicationContext applicationContext) throws Exception {
ProcessEngineFactoryBean pe = new ProcessEngineFactoryBean();
pe.setProcessEngineConfiguration(pec);
pe.setApplicationContext(applicationContext);
return pe.getObject();
}
#Bean
public ProcessEngineConfigurationImpl getProcessEngineConfiguration(
DataSource dataSource,
PlatformTransactionManager transactionManager,
ApplicationContext context) {
SpringProcessEngineConfiguration pec = new SpringProcessEngineConfiguration();
pec.setDataSource(dataSource);
pec.setDatabaseSchemaUpdate("true");
pec.setJobExecutorActivate(true);
pec.setHistory("full");
pec.setMailServerPort(2025);
pec.setDatabaseType("mysql");
pec.setTransactionManager(transactionManager);
pec.setApplicationContext(context);
return pec;
}
#Bean
public RuntimeService getRuntimeService(ProcessEngine processEngine) {
return processEngine.getRuntimeService();
}
...
}
Also, maybe order of context creation has somethong to do with this.
Everything looks OK, I believe it might be something as simple as the subscription service not being scanned (does it belong to package cz.muni.fi.cep?), or Spring assigning another name to the subscription service bean (i.e. dbSubscriptionService or dBSubscriptionService instead of just subscriptionService).
Try replacing #Service in DBSubscriptionService class by #Service("subscriptionService") and it should work.
Related
I'm looking for a lighter way of unit-testing my spring-integration-http gateways than by using SpringBootTest. I'd like to see if I can attach my spring-integration handlers to Jetty directly.
As a trivial example gateway, I'm using this gateway and chain/channel:
<!-- test-app/service.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
...
<int-http:inbound-gateway
request-channel="requestChannel"
supported-methods="GET"
path="/test">
<int-http:request-mapping produces="application/json" />
</int-http:inbound-gateway>
<int:channel id = "requestChannel" />
<int:chain input-channel = "requestChannel" >
<int:transformer expression="'{ "today" : "JUBILEE" }'" />
</int:chain>
</beans>
I can wrap this into a SpringBoot application and then test it using rest-assured and SpringBootTest. This works fine but is fairly slow and heavy-weight:
#SpringBootApplication
#ImportResource({"classpath:test-app/service.xml"})
public class JettyIntSpringBootApp {
public static void main(String[] args) {
SpringApplication.run(JettyIntSpringBootApp.class, args);
}
}
#RunWith(SpringRunner.class)
#SpringBootTest(classes = JettyIntSpringBootApp.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UsingSpringBootTest {
#LocalServerPort
int localServerPort;
#Test
public void can_get_spring_boot_server() {
callGet("test")
.then()
.assertThat().statusCode(200)
.assertThat().body("today", equalTo("JUBILEE"));
}
private Response callGet(final String resource) {
return RestAssured
.given(getMinimalSpecBuilder())
.get(resource);
}
private RequestSpecification getMinimalSpecBuilder() {
return new RequestSpecBuilder()
.setPort(localServerPort)
.setBaseUri("http://localhost:" + localServerPort + "/")
.setContentType(ContentType.JSON)
.setAccept(ContentType.JSON)
.build();
}
}
To try to get the equivalent to run directly in Jetty without the spring-boot overhead, I've created a separate context for the Jetty server, as described in the eclipse documentation: https://www.eclipse.org/jetty/documentation/jetty-9/index.html#framework-jetty-spring
<beans> <!-- test-app/jetty.xml -->
<bean id="contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection" />
<bean id="server" name="Main" class="org.eclipse.jetty.server.Server" init-method="start" destroy-method="stop">
<constructor-arg>
<bean id="threadPool" class="org.eclipse.jetty.util.thread.QueuedThreadPool">
<property name="minThreads" value="10"/>
<property name="maxThreads" value="50"/>
</bean>
</constructor-arg>
<property name="connectors">
<list>
<bean id="connector" class="org.eclipse.jetty.server.ServerConnector">
<constructor-arg ref="server"/>
<property name="port" value="9091"/>
</bean>
</list>
</property>
<property name="handler">
<bean id="handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
<property name="handlers">
<list>
<ref bean="contexts"/>
<bean id="defaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>
</list>
</property>
</bean>
</property>
</bean>
</beans>
I then use SpringRunner to load up the Jetty context configuration with original SpringIntegration service configuration containing the http inbound gateway and chain:
#RunWith(SpringRunner.class)
#ContextConfiguration(locations = { "classpath:test-app/jetty.xml",
"classpath:test-app/service.xml" } )
public class JettyServerTest {
#Test
public void can_get_jetty_server() {
callGet("test")
.then()
.log().all()
.assertThat().statusCode(200)
.assertThat().body("today", equalTo("JUBILEE"));
}
private Response callGet(final String resource) {
return RestAssured
.given(getMinimalSpecBuilder())
.get(resource);
}
private RequestSpecification getMinimalSpecBuilder() {
return new RequestSpecBuilder()
.setPort(9091)
.setBaseUri("http://localhost:" + 9091 + "/")
.setContentType(ContentType.JSON)
.setAccept(ContentType.JSON)
.build();
}
}
This second test fails. The SpringIntegration context is loaded and the Jetty server is also loaded and allows the RestAssured client to connect. However, the "servlet handler" for SpringIntegration is not loaded into the Jetty server, hence the call to Jetty returns a 404 "Resource not found". Jetty is not configured with the SpringIntegration gateway handler.
I'm thinking that there must be a simple way of including either the SpringIntegration DispatcherServlet or the HttpRequestHandlingMessagingGateway as a handler in the Jetty server context, probably via the contexts bean of the jetty.xml configuration. I've tried a number of avenues but no success, hence my post. All pointers appreciated.
I've got a problem in my standalone Java application. The thing is that I'm trying to Autowire both my Services and my DAOs, but I get a NullPointerException when I invoke service methods from the UI since dependency injection is not working properly. I've tried a lot of things, many of them from similar questions, but the problem is still there. I'm using Spring 4.0.6.RELEASE and Hibernate 4.3.11.Final. Here is my code:
1 - Invocation of service:
public class LoginView {
#Autowired
private UsuarioService usuarioService;
...
...
JButton btnAutenticarse = new JButton("Autenticar");
btnAutenticarse.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
Usuario usuario = usuarioService.login(textField.getText(),
String.valueOf(passwordField.getPassword()), false); // NullPointerException
} catch (InstanceNotFoundException e1) {
...
2 - Definition of service:
#Service("usuarioService")
public class UsuarioServiceImpl implements UsuarioService {
#Autowired
private UsuarioDao usuarioDao;
...
3 - Definition of DAO:
#Repository("usuarioDao")
public class UsuarioDaoHibernate extends GenericDaoHibernate <Usuario, Long>
implements UsuarioDao {
...
4 - Definition of GenericDAO:
public class GenericDaoHibernate<E, PK extends Serializable> implements
GenericDao<E, PK> {
#Autowired
private SessionFactory sessionFactory;
....
5 - AppConfig.java:
#Configuration
#ComponentScan(basePackages = "org.example.model")
public class AppConfig {
#Bean(name = "usuarioService")
public UsuarioService usuarioService() {
return new UsuarioServiceImpl();
}
#Bean(name = "usuarioDao")
public UsuarioDao usuarioDao() {
return new UsuarioDaoHibernate();
}
6 - spring-config.xml:
<!-- Enable usage of #Autowired. -->
<context:annotation-config/>
<!-- Enable component scanning for defining beans with annotations. -->
<context:component-scan base-package="org.example.model"/>
<!-- For translating native persistence exceptions to Spring's
DataAccessException hierarchy. -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/appdb" />
<property name="username" value="username" />
<property name="password" value="password"/>
</bean>
<bean id="dataSourceProxy" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy"
p:targetDataSource-ref="dataSource"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" >
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan">
<list>
<value>org.example.model</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<!-- Enable the configuration of transactional behavior based on
annotations. -->
<tx:annotation-driven transaction-manager="transactionManager" />
Spring will only inject Autowired fields in Spring managed beans. AKA if you are using new LoginView() Spring cannot inject dependencies.
public class LoginView {
#Autowired
private UsuarioService usuarioService;
}
should be
#Component
public class LoginView {
#Autowired
private UsuarioService usuarioService;
}
If you can't let Spring manage that class, you'll need to design it a different way.
I'd recommend you use constructor injection instead of field injection, by the way.
What I might do is make another class to be a Spring managed bean and do something like this:
#Component
public class InitClass{
private UsarioService usarioService;
#Autowired
public InitClass(UsarioService usarioService){
this.usarioService = usarioService;
}
#PostConstruct
public void init(){
new LoginView(usarioService);
}
}
Then this class will handle all the initialization you're doing now in #PostConstruct. It may be required to do this in #PostConstruct as Spring beans may not be fully initialized until then.
However, without seeing how everything is initialized, it's hard to tell what the best strategy would be.
Make explicit component scan in the application context file. I did like this and it worked for me.
<context:component-scan base-package="com.example" />
You can see more information in the link here
I want to create a RESTfull web service using Spring + CXF without XML bean configuration. How can I convert the below XML based configuration into Java ?
applicationBean.xml
<jaxrs:server id="employeeService" address="/employeeservices">
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
</jaxrs:providers>
<jaxrs:serviceBeans>
<ref bean="cxfServiceImpl" />
</jaxrs:serviceBeans>
<jaxrs:extensionMappings>
<entry key="xml" value="application/xml" />
<entry key="json" value="application/json" />
</jaxrs:extensionMappings>
</jaxrs:server>
Spring CXF configuration
#Configuration
public class AppConfig {
//Code for CXF need to be here
}
if you are using spring-boot, here is the simplest way.
#Import(SpringComponentScanServer.class)
#Configuration
public class KpCxfConfiguration {
#Bean
public ServletRegistrationBean servletRegistrationBean(ApplicationContext context) {
return new ServletRegistrationBean(new CXFServlet(), "/api/*");
}
}
Note: your service classes needs to be annotated with #Path annotation
And if you are using non-spring boot application you can define servlet mapping in web.xml
When I try to load a resource, it never gets loaded and instead comes back as null. My code is as follows:
Controller.java
#Controller
#Path("/users")
public class UsersAPI {
#Resource(name = "dataLoaderList")
private List<DataLoader> dataLoaderList;
}
spring.xml
<context:component-scan base-package="com.my.package" />
<import resource="classpath:spring/commons.xml" />
<import resource="spring-dataloader.xml" />
<import resource="spring-security.xml" />
spring-dataloader.xml
<bean id="dataLoaderList"
class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list>
<ref bean="dataLoader1" />
<ref bean="dataLoader2" />
<ref bean="dataLoader3" />
</list>
</property>
</bean>
What could I be missing?
EDIT:
I tried loading the resource in a JUnit Test, and it worked. So I have no idea why it wouldn't work in my Controller.
junit
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:spring/spring.xml")
#ActiveProfiles("dev")
public class Test {
#Resource(name = "dataLoaderList")
private List<DataLoader> dataLoaderList;
}
I had to change #Controller annotation to #Component and that fixed my error. I have no idea why it worked.
I have the following in my class:
public class Manager {
private Apple apple = AppleFactory.createInstance();
// .....
}
appContext.xml:
<bean id="manager" class="Manager"/>
AppleFactory is an external library on which I do not have any control over. I use xml configuration(appContext.xml) for wiring the beans. How can I inject the field apple from appContext.xml?
<bean id="apple" class="AppleFactory" factory-method="createInstance" />
<bean id="manager" class="Manager"/>
<context:annotation-config />
Your manager
public class Manager {
#Autowired
private Apple apple;
}
Should do the trick.
See the reference guide and Initializing Spring bean from static method from another Class?
You can use following configuration :
<bean id="apple" class="jarpackagename.AppleFactory"
factory-method="createInstance">
</bean>
<bean id="manager" class="pkgname.Manager">
<property name="apple" ref="apple">
</bean>
You can configure Manager bean as follows
<bean class="xxx.Manager">
<property name="apple">
<bean class="yyy.AppleFactory" factory-method="createInstance" />
</property>
</bean>