I'm trying to load some data to my DB on application start. I have a bean defined for this purpose
applicationContext.xml
<bean class="com.project.loader.DataLoader"
id="DataLoader"
depends-on="entityManagerFactory"
scope="singleton"/>
class:
#RooJavaBean
#RooConfigurable
public class DataLoader implements InitializingBean
It is being executed however on first persist() method being call, Spring throws me following error:
Caused by: java.lang.IllegalStateException: Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)
at com.project.lib.model.extensions.i18n.Locale_Roo_Jpa_ActiveRecord.entityManager_aroundBody0(Locale_Roo_Jpa_ActiveRecord.aj:19)
at com.project.lib.model.extensions.i18n.Locale_Roo_Jpa_ActiveRecord.ajc$interMethod$com_project_lib_model_extensions_i18n_Locale_Roo_Jpa_ActiveRecord$com_project_lib_model_extensions_i18n_Locale$entityManager(Locale_Roo_Jpa_ActiveRecord.aj:1)
at com.project.lib.model.extensions.i18n.Locale.entityManager(Locale.java:1)
Previousely it was working when I defined DataLoader in following way:
#Component
#Configurable
public class DataLoader implements ApplicationListener
but using raw types is not good practice so I would like to switch
How can I make it work?
Spring version: 3.1
I've solved this issue in the past by moving the component-scan definition to the end of the application context, as suggested here
I use the spring SmartLifecycle:
http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/context/SmartLifecycle.html
I've created a class that does this nicely, just extend and override the run method:
public abstract class StartupService implements SmartLifecycle {
/** Logger for this class and subclasses */
protected static final Logger logger = LoggerFactory.getLogger(StartupService.class);
protected boolean running=false;
////////////////////// Lifecycle Methods \\\\\\\\\\\\\\\\\\
#Override
public void start() {
try {
logger.info("starting {}", this.getClass().getSimpleName());
run();
} catch (Exception e) {
logger.error("failed to run importer", e);
}
}
#Override
public void stop() {
running=false;
}
#Override
public boolean isRunning() {
return running;
}
////////////////////// SmartLifecycle Methods \\\\\\\\\\\\\\\\\\
#Override
public boolean isAutoStartup() {
return true;
}
#Override
public void stop(Runnable callback) {
stop();
callback.run();
}
#Override
public int getPhase() {
return 0;
}
public abstract void run() throws Exception;
}
Related
I have created a spring boot application in which I want to use Web Sockets. When I am using it without parameters its working fine. Below is the code without the parameters
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new ABC(), "/getABC").setAllowedOrigins("*");
registry.addHandler(new XYZ(), "/getXYZ").setAllowedOrigins("*");
}
}
But now I need to pass a parameter to it using #PathParam. I am not able to use it in this configuration like
registry.addHandler(new XYZ(), "/getXYZ{someId}").setAllowedOrigins("*");
My Handler code:
public class XYZ extends TextWebSocketHandler {
static List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
String someId;
public XYZ() {
}
public XYZ(#PathParam(value = "someId") String someId) {
this.someId= someId;
}
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
// the messages will be broadcasted to all users.
sessions.add(session);
}
}
I think there is some problem with the syntax, try using
public XYZ(#PathParam("someId") String someId)
I have this service bean with a sync method calling the internal async method:
#Service
public class MyService {
public worker() {
asyncJob();
}
#Async
void asyncJob() {
...
}
}
The trouble is that the asyncJob is not really called in async way.
I found that this doesn't work because an internal call skips the AOP proxy.
So I try to self-refer the bean:
#Service
public class MyService {
MyService mySelf;
#Autowired
ApplicationContext cnt;
#PostConstruct
public void init() {
mySelf=(MyService)cnt.getBean("myService");
}
public void worker() {
mySelf.asyncJob();
}
#Async
void asyncJob() {
...
}
}
It fails. Again no async call.
So I tried to divide it in two beans:
#Service
public class MyService {
#Autowired
MyAsyncService myAsyncService;
public void worker() {
myAsyncService.asyncJob();
}
}
#Service
public class MyAsyncService {
#Async
void asyncJob() {
...
}
}
Fails again.
The only working way is to call it from a Controller Bean:
#Controller
public class MyController {
#Autowired
MyAsyncService myAsyncService;
#RequestMapping("/test")
public void worker() {
myAsyncService.asyncJob();
}
}
#Service
public class MyAsyncService {
#Async
public void asyncJob() {
...
}
}
But in this case it is a service job. Why I cannot call it from a service?
Found a really nice way to solve this (with java8) in the case where you have a lot of various things you want to both sync and async. Instead of creating a separate XXXAsync service for each 'synchronous' service, create a generic async service wrapper:
#Service
public class AsyncService {
#Async
public void run(final Runnable runnable) {
runnable.run();
}
}
and then use it as such:
#Service
public class MyService {
#Autowired
private AsyncService asyncService;
public void refreshAsync() {
asyncService.run(this::refresh);
}
public void refresh() {
// my business logic
}
public void refreshWithParamsAsync(String param1, Integer param2) {
asyncService.run(() -> this.refreshWithParams(param1, param2));
}
public void refreshWithParams(String param1, Integer param2) {
// my business logic with parameters
}
}
I solved the third method (divide it in two beans) changing the async method's access modifier to public:
#Service
public class MyService {
#Autowired
MyAsyncService myAsyncService;
public void worker() {
myAsyncService.asyncJob();
}
}
#Service
public class MyAsyncService {
#Async
public void asyncJob() { // switched to public
...
}
}
In my case, it was easier to remove the #Async annotation and use the taskExecutor directly to submit my task:
Before
#Async("taskExecutor")
private Future<U> executerEnAsync(
final T pInput) {
final U resultat = this.appelerBS(pInput);
return new AsyncResult<U>(resultat);
}
After
#Autowired
private AsyncTaskExecutor taskExecutor;
private Future<U> executerEnAsync(
final T pInput) {
final Future<U> future = taskExecutor.submit(new Callable<U>() {
#Override
public U call() {
final U resultat = appelerBS(pInput);
return resultat;
}
});
return future;
}
So I am testing a simple Google Guice interceptor -
My Annotation -
#Retention(RetentionPolicy.RUNTIME) #Target(ElementType.METHOD)
public #interface AppOpsOperation {
}
My Interceptor
public class AppOpsOperationDecorator implements MethodInterceptor {
private ServiceCallStack callStack = null ;
#Inject
public void setServiceCallStack(ServiceCallStack stack ){
callStack = stack ;
}
#Override
public Object invoke(MethodInvocation arg0) throws Throwable {
// Retrieve the call stack
// exclude service population if caller service is the same service
// else push the current service onto top of stack
System.out.println("Intercepting method -- :: " + arg0.getMethod().getName());
System.out.println("On object - :: " + arg0.getThis().getClass().getName());
System.out.println("On accessible object - :: " + arg0.getStaticPart().getClass().getName());
return invocation.proceed();
}
}
And now my Service interface and method
public interface MockCalledService extends AppOpsService {
#AppOpsOperation
public String methodOneCalled(String some);
#AppOpsOperation
public String methodTwoCalled(String some);
}
public class MockCalledServiceImpl extends BaseAppOpsService implements MockCalledService {
#Override
#AppOpsOperation
public String methodOneCalled(String some) {
System.out.println("MockCalledServiceImpl.methodOneCalled()");
return this.getClass().getCanonicalName() + "methodOneCalled";
}
#Override
public String methodTwoCalled(String some) {
System.out.println("MockCalledServiceImpl.methodTwoCalled()");
return this.getClass().getCanonicalName() + "methodTwoCalled";
}
}
And my Guice test module
public class MockTestGuiceModule extends AbstractModule {
#Override
protected void configure() {
bind(ServiceCallStack.class).toInstance(new ServiceCallStack());
AppOpsOperationDecorator decorator = new AppOpsOperationDecorator() ;
requestInjection(decorator);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AppOpsOperation.class),
decorator);
bind(MockCalledService.class).toInstance(new MockCalledServiceImpl());
}
}
This interceptor doesn't execute when I run the test below -
public class AppOpsOperationDecoratorTest {
private Injector injector = null ;
#Before
public void init(){
injector = Guice.createInjector(new MockTestGuiceModule());
}
#Test
public void testDecoratorInvocation() {
MockCalledService called = injector.getInstance(MockCalledService.class);
called.methodOneCalled("Test String");
}
}
Can you please highlight what I am doing wrong ?
I am answering after finding the real reason. Its so simple that its really tricky.
Method interception only works if you bind the interface with the class and not an instance of this implementation.
so instead of bind(MockCalledService.class).toInstance(new MockCalledServiceImpl());
we should write bind(MockCalledService.class).to(MockCalledServiceImpl.class);
Seems instances are not proxied :(
How can I set up an aop MethodInterceptor to work with Jersey resources?
Here is what I've tried, following this documentation:
Step 1 - InterceptionService
public class MyInterceptionService implements InterceptionService
{
private final Provider<AuthFilter> authFilterProvider;
#Inject
public HK2MethodInterceptionService(Provider<AuthFilter> authFilterProvider)
{
this.authFilterProvider = authFilterProvider;
}
/**
* Match any class.
*/
#Override
public Filter getDescriptorFilter()
{
return BuilderHelper.allFilter();
}
/**
* Intercept all Jersey resource methods for security.
*/
#Override
#Nullable
public List<MethodInterceptor> getMethodInterceptors(final Method method)
{
// don't intercept methods with PermitAll
if (method.isAnnotationPresent(PermitAll.class))
{
return null;
}
return Collections.singletonList(new MethodInterceptor()
{
#Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable
{
if (!authFilterProvider.get().isAllowed(method))
{
throw new ForbiddenException();
}
return methodInvocation.proceed();
}
});
}
/**
* No constructor interception.
*/
#Override
#Nullable
public List<ConstructorInterceptor> getConstructorInterceptors(Constructor<?> constructor)
{
return null;
}
}
Step 2 - Register the service
public class MyResourceConfig extends ResourceConfig
{
public MyResourceConfig()
{
packages("package.with.my.resources");
// UPDATE: answer is remove this line
register(MyInterceptionService.class);
register(new AbstractBinder()
{
#Override
protected void configure()
{
bind(AuthFilter.class).to(AuthFilter.class).in(Singleton.class);
// UPDATE: answer is add the following line
// bind(MyInterceptionService.class).to(InterceptionService.class).in(Singleton.class);
}
});
}
}
However this doesn't appear to work because none of my resource methods are being intercepted. Could this be because I use #ManagedAsync with all of my resources? Any ideas?
Also, please do not suggest a ContainerRequestFilter. See this question for why I can't use one to handle security.
I think that rather than calling register(MyInterceptionService.class) you might want to instead add into your configure() statement:
bind(MyInterceptionService.class).to(InterceptionService.class).in(Singleton.class)
I am not sure it will work as I have not tried it myself so your results may vary lol
I am using Guice with JDO and Datanucleus in my desktop app. I am facing a NPE that I can't fix, so I hope someone can help me :)
I am using properly configured H2 db, with schema created and all my classes are nicely enhanced, so it's not that. Anyway, I am getting NPE here, at JDORepository class:
public abstract class JdoRepository<T> implements Repository<T>
{
private final Class<T> clazz;
private final Provider<PersistenceManager> pmProvider;
protected JdoRepository(Class<T> clazz, Provider<PersistenceManager> pmProvider)
{
this.clazz = clazz;
this.pmProvider = pmProvider;
}
public void persist(T entity)
{
pmProvider.get().makePersistent(entity); <---- NPE!
}
My PersistenceManagerFilter looks like that:
#Singleton
public class PersistenceManagerFilter implements Filter
{
private static final Logger logger = Logger.getLogger(PersistenceManagerFilter.class.getName());
private static final ThreadLocal<PersistenceManager> pm = new ThreadLocal<PersistenceManager>();
private PersistenceManagerFactory pmf;
public void init(FilterConfig filterConfig) throws ServletException
{
logger.info("Creating PersistenceManagerFactory");
pmf = JDOHelper.getPersistenceManagerFactory();
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
try
{
pm.set(pmf.getPersistenceManager());
chain.doFilter(request, response);
}
finally
{
pm.get().close();
}
}
public void destroy()
{
logger.info("Closing PersistenceManagerFactory");
pmf.close();
}
/**
* This module binds the JDO {#link javax.jdo.PersistenceManager} interface to the provider that allows the
* implementation to be injected as Provider<PersistenceManager>.
*/
public static class GuiceModule extends AbstractModule
{
#Override
protected void configure()
{
bind(PersistenceManager.class).toProvider(new Provider<PersistenceManager>()
{
public PersistenceManager get()
{
return PersistenceManagerFilter.pm.get();
}
});
}
}
}
And the responsible module:
public class GuiceModule extends AbstractModule
{
#Override
protected void configure()
{
// Enable per-request-thread PersistenceManager injection.
install(new PersistenceManagerFilter.GuiceModule());
bind(new TypeLiteral<Repository<Project>>() { }).to(JdoProjectRepository.class);
I am initiating it all that way:
Injector injector = Guice.createInjector(new GuiceModule());
Main main = injector.getInstance(Main.class);
main.run();
So repository bindings in main class work fine, as they are redirected to JDORepository. It's something at lower level, PMF not getting bound properly? Any ideas?
What does your main.run()-method do? Does it call PersistenceManagerFilter#doFilter? If it doesn't, the value in yourThreadLocal<PersistenceManager> will be null...
You could override the initialValue() and do something like this:
ThreadLocal<PersistenceManager> pm = new ThreadLocal<PersistenceManager>(){
#Override
protected PersistenceManager initialValue() {
return JDOHelper.getPersistenceManagerFactory().getPersistenceManager();
}
};
You should also remember to call the ThreadLocal#remove() method in your finally-block.
Instead of handling the ThreadLocal yourself, you could bind the PersistenceManager directly in the guice-module:
class GuiceModule extends AbstractModule {
#Provides #RequestScoped
PersistenceManager providePersistenceManager(){
return JDOHelper.getPersistenceManagerFactory().getPersistenceManager();
}
#Override
protected void configure() {}
}