Alfresco Process Services with TaskListener #Autowired issue - spring-boot

I am using Alfresco Process Services and have created a created a spring boot project for custom logic like TaskListeners and Delegations. I am creating the jar file from this maven project and copying it into webapps/activiti-app/WEB-INF/lib folder.
I have a simple TaskListener as below which is getting called on Task start. But the #Autowired variables are always null.
package com.activiti.extension.bean;
#Component("myTaskListener")
public class MyTaskListener implements TaskListener {
#Autowired
UserService userService;
#Override
public void notify(DelegateTask task) {
logger.info("userService: " +userService); // Always prints null
}

Finally I was able to make it work. I was putting the task listener in the class field of the Task properties with full package name. Now I am putting Delegate expression like ${myTaskListener} and it worked...
Thank you all for your time and help

This is because your your MyTaskListener is annotated as #Component or at least being ignored by spring during init. for auto-wiring capabilities spring requires this annotation (or similar to this) under the provided #ComponentScan packages to consider the class as a bean otherwise it will take as a normal java class and hence the #autowired is of no use in your case.

This below code is worked for me
#Component
public class MyTaskListener implements TaskListener {
public static UserService getUserServiceObject() {
return SpringApplicationContextHolder.getApplicationContext().getBean(UserService.class);
}
#Override
public void notify(DelegateTask delegateTask) {
//UserService Object, It is not null now
getUserServiceObject();
}
}
#Component
public class SpringApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}

There is also one more way to get to your custom service "UserService" using Alfresco Spring Application context.
First access ServiceRegistry (registry used for accessing Alfresco Services but also any other custom service):
ServiceRegistry serviceRegistry = (ServiceRegistry) Context.getProcessEngineConfiguration().getBeans().get(ActivitiConstants.SERVICE_REGISTRY_BEAN_KEY);
Then get custom service UserService:
QName qname = QName.createQName("UserService");
UserService userService = (UserService) serviceRegistry.getService(qname);

Related

Spring Data Rest: #Autowire in Custom JsonDeserializer

I am trying to autowire a component into a custom JsonDeserializer but cannot get it right even with the following suggestions I found:
Autowiring in JsonDeserializer: SpringBeanAutowiringSupport vs HandlerInstantiator
Right way to write JSON deserializer in Spring or extend it
How to customise the Jackson JSON mapper implicitly used by Spring Boot?
Spring Boot Autowiring of JsonDeserializer in Integration test
My final goal is to accept URLs to resources in different microservices and store only the ID of the resource locally. But I don't want to just extract the ID from the URL but also verify that the rest of the URL is correct.
I have tried many things and lost track a bit of what I tried but I believe I tried everything mentioned in the links above. I created tons of beans for SpringHandlerInstantiator, Jackson2ObjectMapperBuilder, MappingJackson2HttpMessageConverter, RestTemplate and others and also tried with setting the SpringHandlerInstantiator in RepositoryRestConfigurer#configureJacksonObjectMapper.
I am using Spring Boot 2.1.6.RELEASE which makes me think something might have changed since some of the linked threads are quite old.
Here's my last attempt:
#Configuration
public class JacksonConfig {
#Bean
public HandlerInstantiator handlerInstantiator(ApplicationContext applicationContext) {
return new SpringHandlerInstantiator(applicationContext.getAutowireCapableBeanFactory());
}
}
#Configuration
public class RestConfiguration implements RepositoryRestConfigurer {
#Autowired
private Validator validator;
#Autowired
private HandlerInstantiator handlerInstantiator;
#Override
public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
validatingListener.addValidator("beforeCreate", validator);
validatingListener.addValidator("beforeSave", validator);
}
#Override
public void configureJacksonObjectMapper(ObjectMapper objectMapper) {
objectMapper.setHandlerInstantiator(handlerInstantiator);
}
}
#Component
public class RestResourceURLSerializer extends JsonDeserializer<Long> {
#Autowired
private MyConfig config;
#Override
public Long deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
ServiceConfig serviceConfig = config.getServices().get("identity");
URI serviceUri = serviceConfig.getExternalUrl();
String servicePath = serviceUri.getPath();
URL givenUrl = p.readValueAs(URL.class);
String givenPath = givenUrl.getPath();
if (servicePath.equals(givenPath)) {
return Long.parseLong(givenPath.substring(givenPath.lastIndexOf('/') + 1));
}
return null;
}
}
I keep getting a NullPointerException POSTing something to the API endpoint that is deserialized with the JsonDeserializer above.
I was able to solve a similar problem by marking my deserializer constructor accept a parameter (and therefore removing the empty constructor) and marking constructor as #Autowired.
public class MyDeserializer extends JsonDeserializer<MyEntity> {
private final MyBean bean;
// no default constructor
#Autowired
public MyDeserializer(MyBean bean){
this.bean = bean
}
...
}
#JsonDeserialize(using = MyDeserializer.class)
public class MyEntity{...}
My entity is marked with annotation #JsonDeserialize so I don't have to explicitly register it with ObjectMapper.

Spring job launcher not able to access services

Hi Still learning hope someone can fill in the blanks
I have JSVC quartz spring batch system that has been running for over a year. The Job launcher needs to connect to 2 spring services that successfully run in other parts of the system. Each service has a number of sql repositories or services injected into it.
Please make note of package declarations. for the application context entry.
package com.mycompany.business.services.impl;
....
#Service
public class BatchProcessService {
private final DomainSepcificRepository1 rep1;
...
private final DomainSepcificRepositoryN repN;
#Inject
public BatchProcessService(Final final DomainSepcificRepository1 rep1,..., final DomainSepcificRepositoryN repN) {
// injected values assigned to instance variables.
}
public List <...> findByCriteria(.....)(
.....
}
}
and
package com.mycompany.business.services.impl;
....
#Service
public class EmailNotificationServiceImpl implements EmailNotificationService {
private UserService userService;
private final MailMessage mailMessage;
private final MailTransport mailTransport;
#Inject
public EmailNotificationServiceImpl(final UserService userService, final MailMessage mailMessage, final MailTransport mailTransport) {
this.userService = userService;
this.mailMessage = mailMessage;
this.mailTransport = mailTransport;
}
.....
public void notifySupportStaff(....){
.....
}
}
In my application context xml file, there is the following line that should allow my job launcher to see and instantiate the above services. I think "base-package=" specifies the packages to look for #services, #components and #repositories that can be injected.
<context:component-scan base-package="com.mycompany.common.batch, com.mycompany.batch, com.mycompany.business.services" >
<context:exclude-filter type="assignable" expression="com.mycompany.common.batch.scheduler.service.MyCompanySchedulerService"/>
</context:component-scan>
I think that #Component should allow this class to see the services and instaniate them and any dependancies (other services) they have.
For some reason the jsvc system only wants to invoke class below with the NO arg constructor. and it is not injecting the 2 services.
My unit tests are able to test the method using the service only if I provide a 2 argument constructor for MOCK services.
lll
Any thoughts on why batch system cannot inject the dependencies?
package com.mycompany.batch.scheduler;
....
#Inject
private BatchProcessService batchProcessService;
#Inject
private EmailNotificationService emailNotificationService;
#Component
public class MyCompanySchedulerJobLauncher extends SchedulerJobLauncher {
public MyCompanySchedulerJobLauncher() {
super();
}
// #Inject
public MyCompanySchedulerJobLauncher(final BatchProcessService batchProcessService, final EmailNotificationService emailNotificationService) {
super();
this.batchProcessService = batchProcessService;
this.emailNotificationService = emailNotificationService;
}
#Override
public int processJob(final JobExecutionContext context) throws JobRestartException, JobExecutionAlreadyRunningException, ParseException {
......
if(batchProcessSerive.findByCriteria(....).size() == 0) {
emailNotificationService.notifySupport(...)
}
}
Well Don't I feel silly.
The problem was that at the point where I was assuming I could/would inject dependancies. The application context was private. Once I made my application context protected and to get the services. all worked

Using Spring autowired Service classes within a Liferay Indexer

I am using Spring #Service classes in my liferay portlet to get and store data. They are injected using the #autowired annotation. Everything is working as expected. When I am trying to use that same approach in a Liferay BaseIndexer subclass (to put data in the search engine) the #autowired annotated classes are all null (not injected).
Is there a way to get these Service classes in the Indexer ?
Best regards,
Daniel
This indexer is not instantiated by Spring, so you won't be able to autowired your service.
But, you could implement a custom ApplicationContextProvider (implementing Spring ApplicationContextAware) and use it in order to inject your service. It should be easy.
You should start creating this class, and let Spring to discover it (be sure that this class is scanned by spring):
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* Created by Alberto Martínez Ballesteros on 18/03/16.
*/
#Component("applicationContextProvider")
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context = null;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
}
Then, you can use this ApplicationContextProvider to inject your service within the indexer class:
For example:
public class CategoryIndexer extends BaseIndexer {
private CategoryService categoryService;
[....]
#Override
protected void doReindex(String className, long classPK) throws Exception {
if (categoryService == null) {
initService();
}
final Category category = categoryService.get(classPK);
doReindex(category);
}
private void initService() {
categoryService = (CategoryService) ApplicationContextProvider.getApplicationContext()
.getBean("categoryService");
}
[....]
As you can see, you can not use #Autowired in this way, but you can inject your bean anyway.
Regards.

Java 8 and Spring 4 : Use autowiring in interface

Java 8 added a new feature by which we can provide method implementation in interfaces.
Is there any way in Spring 4 by which we can inject beans in the interface which can be used inside the method body?
Below is the sample code
public interface TestWiring{
#Autowired
public Service service;// this is not possible as it would be static.
//Is there any way I can inject any service bean which can be used inside testWiringMethod.
default void testWiringMethod(){
// Call method of service
service.testService();
}
}
This is a bit tricky but it works if you need the dependency inside the interface for whatever requirement.
The idea would be to declare a method that will force the implemented class to provide that dependency you want to autowire.
The bad side of this approach is that if you want to provide too many dependencies the code won't be pretty since you will need one getter for each dependency.
public interface TestWiring {
public Service getService();
default void testWiringMethod(){
getService().testService();
}
}
public class TestClass implements TestWiring {
#Autowire private Service service;
#Override
public Service getService() {
return service;
}
}
You can created Class utils of application context and use it everywhere even not bean class .
you can have code somethins this :
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext context) {
ApplicationContextUtil.applicationContext = context;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}
and add this to your spring configuration
<bean class="com.example.ApplicationContextUtil" id="applicationContextUtil"/>
now simple to use when you need :
ApplicationContextUtil.getApplicationContext().getBean(SampleBean.class)
this word in web and simple spring app.

why can't I access ApplicationContext from ApplicationContextAware implemented bean

I have a Spring JUnit tester class MySimpleTester:
#
RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:/spring/mySimpleConfig.xml"})
public class MySimpleTester {
#Before
public void setUp() throws Exception {
myAdapter = (MyAdapter) applicationContext.getBean("myAdapter");
}
#test
public void testGetSimpleList() {
List<SimpleLink> simpleList = **myAdapter.getSimpleLinksList**();
}
...
...
In the adapter class I have:
public MyAdapter {
public List<SimpleLink> getSimpleLinksList() {
List<SimpleLink> simLinks = null;
String environment = AppFactory.getPropertiesObj();
...
...
class AppFactory implements ApplicationContextAware {
private static ApplicationContext context;
public void setApplicationContext(ApplicationContext acontext) {
context = acontext;
}
public getPropertiesObj() {
return getAppContext().getBean("propertiesBean");
}
I get NullPointerException and see that ApplicationContext is Null here.
However at the SpringJUnitTestRunner class MySimpleTester I could find the applicationContext to be initialized correctly. I am not including the mySimpleConfig.xml and included files. The method in MyAdapter class getSimpleLinksList() works perfectly fine from the web application when run in the application server, and the appcontext is obtained there.
Only from the Spring tester is it not able to reach the static application context AppFactory class, as it is called statically through AppFactory.getPropertiesObj(). I had the classpath set correctly as other test classes are executing.
If you want to access the current ApplicationContext in MySimpleTester:-
public class MySimpleTester {
#Autowired
ApplicationContext applicationContext;
#Before
public void setUp() throws Exception {
myAdapter = (MyAdapter) applicationContext.getBean("myAdapter");
}
#test
public void testGetSimpleList() {
List<SimpleLink> simpleList = **myAdapter.getSimpleLinksList**();
}
I think it is happening as multiple application contexts are created. The AplliCationContext object is supposed to be singleton. But when from the static method we call the applicationContext again it is refering to altogether different confirguration. The ApplicationContext is not even initialised there.
This does not happen when the same module is called from Spring MVC webcontanier. It happens only when you try to use Spring tester classes RunWith(SpringJUnit4ClassRunner.class). I can pass the AppContext in the business method but I do not want to change the bsiness method signature. I found some threads in spring community with similar issue.

Resources