Can I use #Async annotation with Grails - java

As per the following spring doc link I can use #Async annotation to make a method call asynchronous. Can I use this facility in Grails from a java src file that I have?
[Update]
This is my java(netty) socket handler class which receives the socket packet.
public class DefaultHandler extends SimpleChannelUpstreamHandler {
private static final Logger LOG = LoggerFactory.getLogger(DefaultHandler.class);
private AggregateSocketData aggregateSocketData;
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
LOG.trace("In messageRecieved method with event: {}",e);
IEvent event = Events.dataInEvent(e.getMessage());
System.out.println(Thread.currentThread().getName());
aggregateSocketData.receiveSocketData(event);
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
throws Exception {
LOG.error("Exception occurred in Default Handler: " ,e.getCause());
}
public AggregateSocketData getAggregateSocketData() {
return aggregateSocketData;
}
public void setAggregateSocketData(AggregateSocketData aggregateSocketData) {
this.aggregateSocketData = aggregateSocketData;
}
}
I have made it a bean in grails- conf - resources.xml
<bean id="defaultECM1240Handler" class="com.appcapture.buildingmgr.netty.DefaultHandler"
scope="prototype">
<property name="aggregateSocketData" ref="binaryDataAggregatorService"></property>
</bean>
And this is my grails service class whose method I have annotated with #Async
class BinaryDataAggregatorService implements AggregateSocketData {
def rawDataService
static transactional = true
#Async
void receiveSocketData(IEvent event) {
println Thread.currentThread().name
log.debug("Going to decode netty packet in receiveSocketData");
Map decodedPacket = decodePacket((INettyPacket)event.getSource())
def rawData = saveRawData (decodedPacket);
log.debug ("Saved raw data, id: ${rawData?.id}")
rawDataService.saveHTTPData(decodedPacket);
}
}
[Update 2] Here is the stack trace for the method call.
Here is the stack. BinaryDataAggregatorService.receiveSocketData(INettyPacket) line: 20
BinaryDataAggregatorService$$FastClassByCGLIB$$82489f62.invoke(int, Object, Object[]) line: not available
MethodProxy.invoke(Object, Object[]) line: 149
Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint() line: 688
Cglib2AopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 150
TransactionInterceptor.invoke(MethodInvocation) line: 110
Cglib2AopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 172
Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 621
BinaryDataAggregatorService$$EnhancerByCGLIB$$1c96985c.receiveSocketData(INettyPacket) line: not available
DefaultHandler.handlePacket(INettyPacket) line: 50
[Update 3]
The grails stack trace on setting the task:annotation-driven element.
011-05-26 17:38:03,109 [main] ERROR context.GrailsContextLoader - Error executing bootstraps: Error creating bean with name 'defaultECM1240Handler' defined in URL [file:./grails-app/conf/spring/resources.xml]: Cannot resolve reference to bean 'binaryDataAggregatorService' while setting bean property 'aggregateSocketData'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'binaryDataAggregatorService': Invocation of init method failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class $Proxy12]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy12
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'defaultECM1240Handler' defined in URL [file:./grails-app/conf/spring/resources.xml]: Cannot resolve reference to bean 'binaryDataAggregatorService' while setting bean property 'aggregateSocketData'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'binaryDataAggregatorService': Invocation of init method failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class $Proxy12]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy12
Thanks,
Abraham

If it is a spring bean - yes, you can. For that you have to annotate it with #Service and have a <context:component-scan base-package="com.foo.bar" />
But to make it easier, you can use a groovy class placed in the grails-app/services - it will be a spring bean automatically
In order to make #Async work, you need <task:annotation-driven/> in the xml config.

I found this while trying to do the same thing. I haven't tried it yet, but maybe it will work.
https://gist.github.com/tux2323/2758723
ETA:
I've modified my Resources.groovy file to match what I found here (http://docs.spring.io/spring/docs/3.0.x/reference/scheduling.html):
xmlns task:"http://www.springframework.org/schema/task"
task.'annotation-driven'('executor':'myExecutor')
task.'executor'('id':'myExecutor', 'pool-size':'5')
My code in the #Async annotation is still using the same thread as far as I can tell.

I've followed step from Jason H answer and it's really help me solve the issue on setting #Async for my service.
xmlns task:"http://www.springframework.org/schema/task"
task.'annotation-driven'('executor':'myUploadExecutor', 'proxy-target-class':true, 'mode':'proxy')
task.'executor'('id':'myUploadExecutor', 'pool-size':'5')
I've add this code in my resources.groovy then you can start using #Async in your code (dont forget to import org.springframework.scheduling.annotation.Async in you class),
without ('proxy-target-class':true, 'mode':'proxy') you will get an error java.lang.ClassCastException: com.sun.proxy.$Proxy is thrown when casting your "Service name".
In my case i'm using #Async running on different thread to add something into DB and if you are using #gorm.AuditStamp for your domain, Spring Security context didnt bound to new thread , you will get createdBy and updatedBy NULL .
To solve this issue i've add :
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL) in my BootStrap.groovy on init .
For more information check out this site:
http://www.ogrigas.eu/spring/2010/04/inherit-spring-security-context-in-child-threads

Related

Java Spring Dependency Injection creates two beans, when there should just be one

I want to enable our application to use Springs Dependency Injection. For some reason, some classes get instantiated twice, which leads to an org.springframework.beans.factory.NoUniqueBeanDefinitionException.
The ID of one Bean is just the simple class name, the other is the full name with a #0 at the end:
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'FDDConnectionFactory' defined in file [W:\Projekte\ocp-ospe\ServiceGruppe\osplus.ocp.service.impl\target\classes\osplus\dynssee\ie\ocp\bs\services\fdd\FDDConnectionFactory.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'osplus.dynssee.ie.ocp.bs.services.fdd.FDDParameterResolver' available: expected single matching bean but found 2: FDDDefaultParameterResolver,osplus.dynssee.ie.ocp.bs.services.fdd.FDDDefaultParameterResolver#0
#Component
public class FDDDefaultParameterResolver implements FDDParameterResolver {
private FremdsystemProviderProvider fremdsystemProviderProvider;
#Autowired
public FDDDefaultParameterResolver(FremdsystemProviderProvider fPP) {
this.fremdsystemProviderProvider = fPP;
}
// Some methods
}
#Component
public class FDDConnectionFactory {
#Autowired
public FDDConnectionFactory(FDDParameterResolver fddParams) {
this.fddParams = fddParams;
}
}
I cut down the class to it's bare minimum, as you can see above. But weirdly enough, I'm unable to recreate another minimal example that exhibits the same behaviour. Some injections just work, others don't.
Anybody got some ideas what might be causing this strange behaviour?
It seems the issues was bound to my company's framework, where they already perform some kind of component-scan on specific packages.

Mock a method bean to avoid NullPointerException

I have a method bean that reads a file and returns a NullPointerException when the file doesn't exist. When I am running tests, I don't expect that file to exist so I want to mock that method bean to return a dummy response. It doesn't seem to be working however, and I'm getting an error like this:
"class":"o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext"
,"rest":"Exception encountered during context initialization -
cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'someName' defined in class path resource
[../../Someconfiguration.class]: Bean instantiation via factory method failed;
nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [className]: Factory method 'someName' threw exception;
nested exception is java.lang.NullPointerException"}
The method looks like this:
#Bean
#Qualifier(SOME_QUALIFIER)
public className someName() {
// read file and return null exception if it doesn't exist
}
Would appreciate any ideas on fixing this.
This seems like a use case for Spring profiles.
Mark this method with a positive profile that is only active in production, or a negative profile that is only active in test:
#Bean #Profile("production")
#Qualifier(SOME_QUALIFIER)
public className someName() {
or
#Bean #Profile("!test")
#Qualifier(SOME_QUALIFIER)
public className someName() {
of course you will have to substitute a test configuration that is active for the test profile.

Spring Autowired Component is null in bean method

I am trying to use an #Autowired variable in an #Configuration class, where a bean is created using #Bean in a method. However the component I need to create the bean with is null.
#Autowired
private JDAListener listener;
#Bean
public ShardManager shardManager() throws LoginException, IllegalArgumentException {
DefaultShardManagerBuilder builder = DefaultShardManagerBuilder.createDefault(this.botToken)
.enableIntents(GatewayIntent.GUILD_MEMBERS)
.setStatus(OnlineStatus.IDLE)
.setShardsTotal(this.totalShards)
.addEventListeners(Arrays.asList(this.listener)); //throws Exception
return builder.build();
}
The Exception I get is as follows:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'config':
Unsatisfied dependency expressed through field 'shardManager'; nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'shardManager' defined in class path resource [dev/teamnight/nightbot/Config.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [net.dv8tion.jda.api.sharding.ShardManager]: Circular reference involving containing bean 'config' - consider declaring the factory method as static for independence from its containing instance. Factory method 'shardManager' threw exception;
nested exception is java.lang.IllegalArgumentException: listeners may not be null
I assume the code snippet is a part of some kind of configuration (Something annotated with #Configuration or maybe even #SpringBootApplication).
In this case:
Make JDAListener be managed by Spring container as well.
Inject the instance of JDAListener bean into the shard manager by passing the parameter to the shardManager method
You will end up with the code that looks like this:
#Configuration
public class MyConfiguration {
#Bean // now jda listener is managed by spring!
public JDAListener jdaListener() {
return new JDAListener();
}
#Bean // note the parameter to the method
public ShardManager shardManager(JDAListener jdaListener) throws LoginException, IllegalArgumentException {
DefaultShardManagerBuilder builder =
DefaultShardManagerBuilder.createDefault(this.botToken)
.enableIntents(GatewayIntent.GUILD_MEMBERS)
.setStatus(OnlineStatus.IDLE)
.setShardsTotal(this.totalShards)
.addEventListeners(Arrays.asList(jdaListener)); //throws Exception
return builder.build();
}
}
I think that you're facing this issue because Spring attempted to dependency inject the bean before it injected the listener. How about you try declare JdaListener as a bean as well?
Is JDAListener is marked as #Component/ #Service or something which tells the framework that it is suppose to be treated as a bean? Also, quickly check your component scan configuration.

Spring Error creating bean with name 'covidController' defined in file

First of all, you may think/vote this question as a duplicate. Let me tell you, I have tried almost every possible solution on SO and not on SO.
I am using the Spring framework for a project and the project is based on a layered architecture. I have tried to fix an exception that is thrown when I start the Spring. I am trying to solve this for the last few days and I was not able to solve it. (I am new to spring)
I have three layers:
domain
persistence
rest
When I start the application, it throws me an error:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'covidController' defined in file [......./layered-architecture-spring/rest/target/classes/com/comp/rest/CovidController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'covidRepository' defined in com.comp.persistence.CovidRepository defined in #EnableJpaRepositories declared on RestApp: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.List com.comp.persistence.CovidRepository.fetchAllData()! No property fetchAllData found for type Covid!
Caused by: java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.List com.comp.persistence.CovidRepository.fetchAllData()! No property fetchAllData found for type Covid!
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property fetchAllData found for type Covid!
at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:94) ~[spring-data-commons-2.3.0.RELEASE.jar:2.3.0.RELEASE]
My whole project on GitHub: https://github.com/Phoenix404/ssa-layered-assignment
#RestController
public class CovidController {
private final CovidRepository covidRepository;
public CovidController(CovidRepository cr) {
covidRepository = cr;
}
#GetMapping("/cdata")
public List<Covid> getList() {
return this.covidRepository.findByLocation("italy");
}
}
#Repository
public interface CovidRepository extends JpaRepository<Covid, Integer> {
List<Covid> fetchAllData();
List<Covid> findByDate(Date date);
List<Covid> findByLocation(String location);
}
CovidController is my Rest app controller inside the rest module. The CovidRepository is in the persistence module.
I am using the following annotations for scanning the classes as suggested on other SO but I am still getting the error:
#SpringBootApplication
#EnableJpaRepositories("com.comp.**persistence**")
#EntityScan(basePackages = {"com.comp.**"})
#ComponentScan(basePackages = {"com.comp.**"})
#SpringBootApplication
#EnableJpaRepositories("com.comp.persistenc*")
#EntityScan(basePackages = {"com.comp"})
#ComponentScan(basePackages = {"com.comp"})
#SpringBootApplication
#EnableJpaRepositories("com.comp.*")
#EntityScan(basePackages = {"com.comp.*"})
#ComponentScan(basePackages = {"com.comp.*"})
What am I doing wrong?
Thanks to #aniket-sahrawat, for solving the question.
The problem is solved, when I removed the methods from my covidRepository.

How can I use YAML properties with constructor injection in Spring Boot?

I know this should be a piece of cake but I'm just not getting anywhere.
In my Spring Boot app, in the application.yml file, I have an entry like so:
some:
constructor:
property: value
And I have a spring service (this is fake but demonstrates the problem):
package somepackage;
#Service
public class DummyService {
public DummyService(#Value("${some.constructor.property}") String path) {}
}
Startup fails, though:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'dummyService' defined in file [...(the class
file)... ]: Instantiation of bean failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to
instantiate [somepackage.DummyService]: No default constructor found;
nested exception is java.lang.NoSuchMethodException:
somepackage.DummyService.()
How can I convince Spring that it should use the non-empty constructor, and it should get that constructor parameter from the YAML file? Note: I'm not using any XML bean config files or anything, and would prefer not to.
Just put the #Autowired annotation on your constructor.
#Autowired
public DummyService(#Value("${some.constructor.property}") String path) {}
And just in case someone else is trying to do this in Scala -- which is what I was really trying to do, but wanted to get the answer in Java before trying it with Scala -- this works:
#Service
class DummyService #Autowired()(#Value("${some.constructor.property}") val path: String) {
}
This is covered in this SO case for scala constructor autowiring.

Categories

Resources