So, this is something of a follow-on of this question. My current code looks something like this:
#Configuration
#EnableAutoConfiguration
#ComponentScan(basePackages = {"base.pkg.name"})
public class MyApp implements ServletContextAware {
private ThingDAO beanThingDAO = null;
public MyApp() {
// Lots of stuff goes here.
// no reference to servletContext, though
// beanThing gets initialized, and mostly populated.
}
#Bean publicD ThingDAO getBeanThingDAO() { return beanThingDAO; }
public void setServletContext(ServletContext servletContext) {
// all references to servletContext go here, including the
// bit where we call the appropriate setters in beanThingDAO
{
}
The problem is, it's not working. Specifically, my understanding was that setServletContext was supposed to be called by various forms of Spring Magic at some point during the startup process, but (as revealed by System.out.println()) it never gets called. I'm trying to finish up the first stage of a major bunch of refactoring, and for the moment it is of notable value to me to be able to handle the access to servletContext entirely inside of the #Configuration file. I'm not looking for an answer that will tell me that I should put it in the controllers. I'm looking for an answer that will either tell me how to get it working inside of the #Configuration file, or explain why that won't work, and what I can do about it.
I just ran into a very similar issue and while I'm not positive it's exactly the same problem I thought I'd record my solution in case it's helpful to others.
In my case I had a single #Configuration class for my spring boot application that implemented both ServletContextAware and WebMvcConfigurer.
In the end it turns out that Spring Boot has a bug (or at least undocumented restraint) that ServletContextAware.setServletContext() will never be called if you also implement WebMvcConfigurer on the same class. The solution was simply to split out a separate #Configuration class to implement ServletContextAware.
Here's a simple project I found that demonstrates and explains more what the problem was for me:
https://github.com/dvntucker/boot-issue-sample
The OP doesn't show that the bean in question was implementing both of these, but given the OP is using simplified example code I thought maybe the fact that the asker could have been implementing both interfaces in his actual code and might have omitted the second interface.
Well, I have an answer. It's not one I'm particularly happy with, so I won't be accepting it, but if someone with my same problem stumbles across this question, I want to at least give them the benefit of my experience.
For some reason, the ServletContextAware automatic call simply doesn't work under those circumstances. It works for pretty much every other component, though. I created a kludge class that looks something like this:
// This class's only purpose is to act as a kludge to in some way get
// around the fact that ServletContextAware doesn't seem to work on MyApp.
// none of the *other* spring boot ways of getting the servlet context into a
// file seem to work either.
#Component
public class ServletContextSetter implements ServletContextAware {
private MyApp app;
public ServletContextSetter(MyApp app) {
this.app = app;
}
#Override
public void setServletContext(ServletContext servletContext) {
app.setServletContext(servletContext);
}
}
Does the job. I don't like it, and I will be rebuilding things later to make it unnecessary so I can take it out, but it does work. I'm going to hold the checkmark, though, in case anyone can tell me either how to make it work entirely inside the #Configuration - decorated file, or why it doesn't work there.
Note that the #Component decorator is important, here. Won't work without it.
Related
Let's say I need to enhance the shower() method with a #MusicAround advice to give me some music before and after executing the shower() method.
public class Me {
#MusicAround
public void shower() {
// shower code omitted
}
}
First I created the new annotation #MusicAround.
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MusicAround {
Then bind it with an aspect MusicAspect.
#Aspect
public class MusicAspect {
#Around("#annotation(MusicAround)")
public Object musicAround(ProceedingJoinPoint joinPoint) throws Throwable {
IPhone iphone = new IPhone();
Iphone.music();
joinPoint.proceed();
iphone.music();
}
}
Configure MusicAspect as a Bean. #EnableAspectJAutoProxy annotation leaves spring to encapsulate the aspect proxy for me.
#Configuration
#EnableAspectJAutoProxy
public class ApplicationConfig {
// ... other beans omitted
#Bean
public MusicAspect musicAspect() {
return new MusicAspect();
}
}
In main method, get Me instance from context, and execute shower() method.
public static void main(String[] args) {
try {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
Me me = context.getBean(Me.class);
me.shower();
context.close();
} catch (ApplicationContextException ace) {
// handle exception
}
}
Now I can enjoin the music during the shower.
<hey jude>
I'm showering
<don't be so serious>
The problem is that in this way MusicAspect class is coupled with IPhone class. I want to decouple them by injecting IPhone object as a parameter as below,
#Aspect
public class MusicAspect {
#Around("#annotation(MusicAround)")
public Object musicAround(ProceedingJoinPoint joinPoint, IPhone iphone) throws Throwable {
iphone.music();
joinPoint.proceed();
iphone.music();
}
}
Of cause a second parameter "iphone" in musicAround() method will not be allowed here. Is there any spring features that I can use to decouple IPhone and MusicAspect in this case?
!Note: thanks #kriegaex for the proofreading.
This is a preliminary answer, because the content is not suitable for a comment.
When looking at the code in your updated question, some things strike me as strange:
I wonder why everyone is so eager to always use aspects in combination with annotations. Why not use a pointcut which directly targets packages, classes or methods of interest? All this annotation pollution is horrible, if not absolutely necessary. Ideally, the application code should be completely agnostic of the existence of aspects.
You use the #annotation pointcut designator incorrectly. Instead of #annotation(#MusicAround) it should be #annotation(MusicAround). But also that only works if the annotation happens to be in the exact same package as the aspect, otherwise you need #annotation(fully.qualified.package.name.MusicAround).
You use a MusicAspect, but then declare a MinstrelAroundAdvice bean. That does not seem to match. Besides, an aspect is an aspect, the method inside it which actually does something is the advice. So the class name *Advice for an aspect is simply wrong. Better use *Aspect instead or something else which properly describes what the aspect does. In this case, MusicAspect seems just fine to me.
Now concerning your actual question, it is still unclear to me. Is it about how to inject (auto-wire) another bean into an aspect instance?
Of course I was not allowed to do so.
Why "of course"? What was not allowed? How did you notice? Did something not work? Did you get an error message? A stack trace? Please explain clearly what you tried, what the expected result is and what happened instead. Make your problem reproducible. Your code snippets do not do that, unfortunately. Just imagine for a minute that someone else would ask you the same question without you seeing the full code and without other context information necessary to understand the problem. Could you answer it? If your helpers do not understand the problem, how can they answer your question? Please be advised to learn what an MCVE is.
Problem solved with the help of #k-wasilewski and #kriegaex. Thanks bro.
The answer is #Autowired annotation.
Define IPhone as a field of MusicAspect class. Add #Autowired tag, which tells spring context to initialize the IPhone instance for us.
#Aspect
public class MusicAspect {
#Autowired
private IPhone iphone;
#Around("#annotation(MusicAround)")
public Object musicAround(ProceedingJoinPoint joinPoint) throws Throwable {
Iphone.music();
joinPoint.proceed();
iphone.music();
}
}
Don't forget to register IPhone bean in ApplicationConfig. The rest part remain the same.
#Configuration
#EnableAspectJAutoProxy
public class ApplicationConfig {
// ... other beans omitted
#Bean
public IPhone iphone() {
return new IPhone();
}
}
The code passed unit-test on my laptop.
My team owns a library that provides components that must be referencable by code that consumes the library. Some of our consumers use Spring to instantiate their apps; others use Guice. We'd like some feedback on best-practices on how to provide these components. Two options that present themselves are:
Have our library provide a Spring Configuration that consumers can #Import, and a Guice Module that they can install.
Have our library provide a ComponentProvider singleton, which provides methods to fetch the relevant components the library provides.
Quick sketches of what these would look like:
Present in both approaches
// In their code
#AllArgsConstructor(onConstructor = #__(#Inject))
public class ConsumingClass {
private final FooDependency foo;
...
}
First approach
// In our code
#Configuration
public class LibraryConfiguration {
#Bean public FooDependency foo() {...}
...
}
---
public class LibraryModule extends AbstractModule {
#Provides FooDependency foo() {...}
...
}
========================
========================
// In their code
#Configuration
#Import(LibraryConfiguration.java)
public class ConsumerConfiguration {
// Whatever initiation logic they want - but, crucially, does
// *not* need to define a FooDependency
...
}
---
// *OR*
public class ConsumerModule extends AbstractModule {
#Override
public void configure() {
// Or, simply specify LibraryModule when creating the injector
install(new LibraryModule());
...
// As above, no requirement to define a FooDependency
}
}
Second approach
// In our code
public class LibraryProvider {
public static final INSTANCE = buildInstance();
private static LibraryProvider buildInstance() {...}
private static LibraryProvider getInstance() {return INSTANCE;}
}
========================
========================
// In their code
#Configuration
public class ConsumerConfiguration {
#Bean public FooDependency foo() {
return LibraryProvider.getInstance().getFoo();
}
...
}
// or equivalent for Guice
Is there an accepted Best Practice for this situation? If not, what are some pros and cons of each, or of another option I haven't yet thought of? The first approach has the advantage that consumers don't need to write any code to initialize dependencies, and that DI frameworks can override dependencies (e.g. with mocked dependencies for testing); whereas the second approach has the advantage of being DI-framework agnostic (if a new consumer wanted to use Dagger to instantiate their app, for instance, we wouldn't need to change the library at all)
I think the first option is better. If your library has inter-dependencies between beans then the code of #Configuration in case of spring in the second approach) will be:
Fragile (what if application doesn't know that a certain bean should be created)
Duplicated - this code will appear in each and every consumer's module
When the new version of your library gets released and a consumer wants to upgrade- there might be changes in consumer's configuration ( the lib might expose a new bean, deprecate or even remove some old stuff, etc.)
One small suggestion:
You can use Spring factories and then you don't even need to make an #Import in case of spring boot. just add a maven dependency and it will load the configuration automatically.
Now, make sure that you work correctly with dependencies in case of that approach.
Since you code will include both spring and Juice dependent code, you'll add dependencies on both for your maven/gradle module of the library. This means, that consumer that uses, say, guice, will get all the spring stuff because of your library. There are many ways to overcome this issue depending on the build system of your choice, just want wanted to bring it up
Basis
I have several projects, which implement a caching service - each its own, and each one is almost the same as the others. I have coompressed and shortened the existing cacheservices into a single project containing two different cache services - one for basic objects, and one for complex objects (which extends the basic service). I have created 2 projects - one to deploy as a .war-file and the API-project for this.
The entire application runs on a JBoss AS 7.1 "Thunder" with the latest JDK 7.
Problem
One class in particular requires to be notified whenever an old cache entry is deleted. For this, I implemented a notification procedure using CleanupListeners.
CleanupListener.java
public interface CleanupListener extends Remote {
public abstract boolean supports(Class<?> clazz) throws RemoteException;
public abstract void notify(Object removedObject) throws RemoteException;
}
necessary implementations in the cache service
public void registerCleanupListener(CleanupListener listener) {
listeners.add(listener);
}
private void fireCleanupEvent(Object removedObject) {
for (CleanupListener cleanupListener : listeners) {
try {
if (cleanupListener.supports(removedObject.getClass())) {
cleanupListener.notify(removedObject);
}
} catch (RemoteException re) {
LOGGER.error("Remote Listener not available", re);
}
}
}
The listeners are managed via a private final HashSet<CleanupListener>
The project which needs to be notified uses this implementation of the interface:
#Component
public class CleanupEventListener extends UnicastRemoteObject implements CleanupListener {
protected CleanupEventListener() throws RemoteException {
super();
}
#Resource
private ClassRequiresNotification notifyMe;
public boolean supports(Class<?> clazz) {
return SupportedObject.class.isAssignableFrom(clazz);
}
public void notify(Object removedObject) {
notifyMe.someMethod((SupportedObject) removedObject);
}
}
and a registration bean:
#Component
public class CleanupEventListenerRegistrator {
#Resource
private CleanupEventListener cleanupEventListener;
#Resource
private BasicCacheService cacheService;
#PostConstruct
public void init() {
cacheService.registerCleanupListener(cleanupEventListener);
}
}
The remote services are exported via SpringBean:
#Bean
public RmiServiceExporter basicCacheServiceExporter(BasicCacheService basicCacheService) {
RmiServiceExporter cacheService = new RmiServiceExporter();
cacheService.setService(basicCacheService);
cacheService.setServiceName(BASIC_CACHE_SERVICE_NAME);
cacheService.setServiceInterface(some.package.BasicCacheService.class);
return cacheService;
}
and registered via XML-Config:
<bean id="basicCacheService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="lookupStubOnStartup" value="false"/>
<property name="serviceUrl" value="basicCacheService" />
<property name="serviceInterface" value="some.package.BasicCacheService" />
<property name="refreshStubOnConnectFailure" value="true"/>
</bean>
Exception
So, whenever I try to call the expected methods, I get one of two Exceptions:
Either I get a NoSuchObjectException (rare) or, much more common a ClassNotFoundException wrapped in an UnmarshalException
What I did
I already consulted the JavaDocs, googled massively and have sifted through several questions here, however to no avail. I found a bit of info that the standard property rmi.codebase is set to true, and this might require some rewriting of code, however we are already using RMI at another place in the projects, and it does work fine there. Adding a SecurityManager breaks the rest of our Application (due to external prerequisites) and calls the NoSuchObjectException.
Answers within StackOverflow so far have yielded "this is a problem with the codebase", "you need to install a securityManager", "the classes have to have the same name and be in the same package" and of course "it's the codebase". I am mentioning this one twice, since it does appear quite often yet not a single mention as to how to deal with a codebase problem accompanies it.
Additional Info
I am not sure if this is important, but here's some more info:
The cacheservice-project is configured in java code, the projects which use the service are configured in XML.
The Listener-Interface is not exported vie Annotations or XML-Beans, since several Posts (including at least one here) hinted that this will export the class, but keep listening only on server-side, which is not what I want.
I have also tried to make the CleanupListeneran abstract class, which in itselt extends UnicastRemoteObject but that did not work out either - in fact, it was worse than what I have now.
I am writing and testing the application in eclipse.
Assembling and publishing to server is done by gradle in the command line.
Question
Does anyone know what the problem here is, and how to actually solve it? It is getting quite aggravating when everything I do is either running into an exception or is "yeah that's a codebase error", since both do not help at all.
Any help would be appreciated.
Actual answer
Okay, this is simultaneously embarrassing and relieving. First of all...
The good news
The Listener-Interface as described above works. It is registered on the server-side, and when called, fires a notification to the client, which then may act accordingly. So, if you have been looking for an answer to the whole "passing a listener"-problem, there you have it.
The bad news
however is that I have been quite ignorant to certain facts. Among other things, what the term codebase actually covers. In my particular case, the problem was that the cacheservice itself had no dependencies on the other projects, which (custom) classes it should preserve. So technically, the codebase actually was the problem - due to lacking dependencies in the build.gradle.
I hope I dodn't waste anyone's time on this, if so, please accept my apologies, and hopefully, this question helps someone else sometime.
I have a weird problem. I created a test class by extending StrutsTestCase.
public class MyActionTest extends StrutsTestCase{
public void helloTest()
{
}
}
The struts documentation says request of MockHttpServletRequest will be available by extending StrutsTestCase. Fair enough, it's a protected variable in StrutsTestCase so we should have access to it once we extend the class.
But for some reason, NO protected attribute or method of StrutsTestCase is visible in my MyActionTest.
I don't know if I am missing something, but everything seems straight forward, but yet doesn't work.
Any idea as to why the protected methods of super class are not accessible in subclass ? Should I use some specific package or something ?
List of jars I use for this task :
spring-2.5.3.jar
spring-mock-1.2.6.jar
struts2-core-2.0.11.jar
xwork-core-2.3.1.jar
Am I missing something ?
Perhaps struts2-junit-plugin http://struts.apache.org/2.x/docs/junit-plugin.html or struts2-testng-plugin http://struts.apache.org/2.x/docs/testng-plugin.html
StrutsTestCase is part of the struts2-junit-plugin. See http://struts.apache.org/2.2.3/struts2-plugins/struts2-junit-plugin/apidocs/org/apache/struts2/StrutsTestCase.html - you'll find the protected request variable there.
Just add that plugin to your classpath and you should be able to use it. Also, don't forget to use the same versions for your struts-core and the plugin.
I am using Spring's declarative transactions (the #Transactional annotation) in "aspectj" mode. It works in most cases exactly like it should, but for one it doesn't. We can call it Lang (because that's what it's actually called).
I have been able to pinpoint the problem to the load time weaver. By turning on debug and verbose logging in aop.xml, it lists all classes being woven. The problematic class Lang is indeed not mentioned in the logs at all.
Then I put a breakpoint at the top of Lang, causing Eclipse to suspend the thread when the Lang class is loaded. This breakpoint is hit while the LTW weaving other classes! So I am guessing it either tries to weave Lang and fails and doesn't output that, or some other class has a reference that forces it to load Lang before it actually gets a chance to weave it.
I am unsure however how to continue to debug this, since I am not able to reproduce it in smaller scale. Any suggestions on how to go on?
Update: Other clues are also welcome. For example, how does the LTW actually work? There appears to be a lot of magic happening. Are there any options to get even more debug output from the LTW? I currently have:
<weaver options="-XnoInline -Xreweavable -verbose -debug -showWeaveInfo">
I forgot tom mention it before: spring-agent is being used to allow LTW, i.e., the InstrumentationLoadTimeWeaver.
Based on the suggestions of Andy Clement I decided to inspect whether the AspectJ transformer is ever even passed the class. I put a breakpoint in ClassPreProcessorAgent.transform(..), and it seems that the Lang class never even reaches that method, despite it being loaded by the same class loader as other classes (an instance of Jetty's WebAppClassLoader).
I then went on to put a breakpoint in InstrumentationLoadTimeWeaver$FilteringClassFileTransformer.transform(..). Not even that one is hit for Lang. And I believe that method should be invoked for all loaded classes, regardless of what class loader they are using. This is starting to look like:
A problem with my debugging. Possibly Lang is not loaded at the time when Eclipse reports it is
Java bug? Far-fetched, but I suppose it does happen.
Next clue: I turned on -verbose:class and it appears as if Lang is being loaded prematurely - probably before the transformer is added to Instrumentation. Oddly, my Eclipse breakpoint does not catch this loading.
This means that Spring is new suspect. there appears to be some processing in ConfigurationClassPostProcessor that loads classes to inspect them. This could be related to my problem.
These lines in ConfigurationClassBeanDefinitionReader causes the Lang class to be read:
else if (metadata.isAnnotated(Component.class.getName()) ||
metadata.hasAnnotatedMethods(Bean.class.getName())) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
return true;
}
In particular, metadata.hasAnnotatedMethods() calls getDeclaredMethods() on the class, which loads all parameter classes of all methods in that class. I am guessing that this might not be the end of the problem though, because I think the classes are supposed to be unloaded. Could the JVM be caching the class instance for unknowable reasons?
OK, I have solved the problem. Essentially, it is a Spring problem in conjunction with some custom extensions. If anyone comes across something similar, I will try to explain step by step what is happening.
First of all, we have a custom BeanDefintionParser in our project. This class had the following definition:
private static class ControllerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
protected Class<?> getBeanClass(Element element) {
try {
return Class.forName(element.getAttribute("class"));
} catch (ClassNotFoundException e) {
throw new RuntimeException("Class " + element.getAttribute("class") + "not found.", e);
}
}
// code to parse XML omitted for brevity
}
Now, the problem occurs after all bean definition have been read and BeanDefinitionRegistryPostProcessor begins to kick in. At this stage, a class called ConfigurationClassPostProcessor starts looking through all bean definitions, to search for bean classes annotated with #Configuration or that have methods with #Bean.
In the process of reading annotations for a bean, it uses the AnnotationMetadata interface. For most regular beans, a subclass called AnnotationMetadataVisitor is used. However, when parsing the bean definitions, if you have overriden the getBeanClass() method to return a class instance, like we had, instead a StandardAnnotationMetadata instance is used. When StandardAnnotationMetadata.hasAnnotatedMethods(..) is invoked, it calls Class.getDeclaredMethods(), which in turn causes the class loader to load all classes used as parameters in that class. Classes loaded this way are not correctly unloaded, and thus never weaved, since this happens before the AspectJ transformer registered.
Now, my problem was that I had a class like so:
public class Something {
private Lang lang;
public void setLang(Lang lang) {
this.lang = lang;
}
}
Then, I had a bean of class Something that was parsed using our custom ControllerBeanDefinitionParser. This triggered the wrong annotation detection procedure, which triggered unexpected class loading, which meant that AspectJ never got a chance to weave Lang.
The solution was to not override getBeanClass(..), but instead override getBeanClassName(..), which according to the documentation is preferable:
private static class ControllerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
protected String getBeanClassName(Element element) {
return element.getAttribute("class");
}
// code to parse XML omitted for brevity
}
Lesson of the day: Do not override getBeanClass unless you really mean it. Actually, don't try to write your own BeanDefinitionParser unless you know what you're doing.
Fin.
If your class is not mentioned in the -verbose/-debug output, that suggests to me it is not being loaded by the loader you think it is. Can you be 100% sure that 'Lang' isn't on the classpath of a classloader higher in the hierarchy? Which classloader is loading Lang at the point in time when you trigger your breakpoint?
Also, you don't mention AspectJ version - if you are on 1.6.7 that had issues with ltw for anything but a trivial aop.xml. You should be on 1.6.8 or 1.6.9.
How does ltw actually work?
Put simply, an AspectJ weaver is created for each classloader that may want to weave code. AspectJ is asked if it wants to modify the bytes for a class before it is defined to the VM. AspectJ looks at any aop.xml files it can 'see' (as resources) through the classloader in question and uses them to configure itself. Once configured it weaves the aspects as specified, taking into account all include/exclude clauses.
Andy Clement
AspectJ Project Lead
Option 1) Aspect J is open source. Crack it open and see what is going on.
Option 2) Rename your class to Bang, see if it starts working
I would not be surprised if there is hard coding to skip "lang' in there, though I can't say why.
Edit -
Seeing code like this in the source
if (superclassnameIndex > 0) { // May be zero -> class is java.lang.Object
superclassname = cpool.getConstantString(superclassnameIndex, Constants.CONSTANT_Class);
superclassname = Utility.compactClassName(superclassname, false);
} else {
superclassname = "java.lang.Object";
}
Looks like they are trying to skip weaving of java.lang.stuff.... don't see anything for just "lang" but it may be there (or a bug)