I built a mailserver in java and I have been providedwith an ObserverProtocol written with AOP. I am using Eclipse with AspectJ plugin as required
I try to use static methods like aspectOf, who I as understand should be added at the weaving step
Eclipse can't seem to make it work as I always get the following error :
Description Resource Path Location Type
The method aspectOf() is undefined for the type ObserverProtocol MailReaderBean.java /emailClent_test/src/emailserver line 86 Java Problem
From what I understood by snooping around various websites, tutorials and documentation, it seems that my .aj files aren't being woven correctly
I tried compiling manually with ajc to no avail, and I tinkered with paths and settings and jars and libs in various ways, nothing seems to work and I can't seem to find a definitive guide or tutorial to setup things correctly
My aspect code :
package protocol;
import java.util.WeakHashMap;
import java.util.List;
import java.util.LinkedList;
import java.util.Iterator;
public abstract aspect ObserverProtocol
{
protected interface Subject { }
protected interface Observer { }
private WeakHashMap perSubjectObservers;
protected List getObservers(Subject s)
{
if (perSubjectObservers == null)
{
perSubjectObservers = new WeakHashMap();
}
List observers = (List)perSubjectObservers.get(s);
if ( observers == null )
{
observers = new LinkedList();
perSubjectObservers.put(s, observers);
}
return observers;
}
public void addObserver(Subject s, Observer o)
{
getObservers(s).add(o);
}
public void removeObserver(Subject s, Observer o)
{
getObservers(s).remove(o);
}
protected abstract pointcut subjectChange(Subject s);
after(Subject s): subjectChange(s)
{
Iterator iter = getObservers(s).iterator();
while ( iter.hasNext() )
{
updateObserver(s, ((Observer)iter.next()));
}
}
protected abstract void updateObserver(Subject s, Observer o);
public static ObserverProtocol aspectOf() {
// TODO Auto-generated method stub
return this;
}
}
Offending code in my java server
//Add observer Proxy for monitoring the subject MailServer.
ObserverProtocol.aspectOf().addObserver(this, proxy );
Is there any resources that could help me understand how weaving works and how to setup my build without resorting to Spring or Maven?
This method (and hasAspect()) is added during weaving. If your aspect was built with javac rather than ajc, then it will not have these methods when jvm starts because the weaver hasn't yet run.
I recommend you read these documents:
Hello World (AspectJ)
Getting Started with AspectJ
Related
Please explain, why self invocation on proxy performed on target but not proxy? If that made on purpose, then why? If proxies created by subclassing, it's possible to have some code executed before each method call, even on self invocation. I tried, and I have proxy on self invocation
public class DummyPrinter {
public void print1() {
System.out.println("print1");
}
public void print2() {
System.out.println("print2");
}
public void printBoth() {
print1();
print2();
}
}
public class PrinterProxy extends DummyPrinter {
#Override
public void print1() {
System.out.println("Before print1");
super.print1();
}
#Override
public void print2() {
System.out.println("Before print2");
super.print2();
}
#Override
public void printBoth() {
System.out.println("Before print both");
super.printBoth();
}
}
public class Main {
public static void main(String[] args) {
DummyPrinter p = new PrinterProxy();
p.printBoth();
}
}
Output:
Before print both
Before print1
print1
Before print2
print2
Here each method called on proxy. Why in documentation mentioned that AspectJ should be used in case of self invocation?
Please read this chapter in the Spring manual, then you will understand. Even the term "self-invocation" is used there. If you still do not understand, feel free to ask follow-up questions, as long as they are in context.
Update: Okay, now after we have established that you really read that chapter and after re-reading your question and analysing your code I see that the question is actually quite profound (I even upvoted it) and worth answering in more detail.
Your (false) assumption about how it works
Your misunderstanding is about how dynamic proxies work because they do not work as in your sample code. Let me add the object ID (hash code) to the log output for illustration to your own code:
package de.scrum_master.app;
public class DummyPrinter {
public void print1() {
System.out.println(this + " print1");
}
public void print2() {
System.out.println(this + " print2");
}
public void printBoth() {
print1();
print2();
}
}
package de.scrum_master.app;
public class PseudoPrinterProxy extends DummyPrinter {
#Override
public void print1() {
System.out.println(this + " Before print1");
super.print1();
}
#Override
public void print2() {
System.out.println(this + " Before print2");
super.print2();
}
#Override
public void printBoth() {
System.out.println(this + " Before print both");
super.printBoth();
}
public static void main(String[] args) {
new PseudoPrinterProxy().printBoth();
}
}
Console log:
de.scrum_master.app.PseudoPrinterProxy#59f95c5d Before print both
de.scrum_master.app.PseudoPrinterProxy#59f95c5d Before print1
de.scrum_master.app.PseudoPrinterProxy#59f95c5d print1
de.scrum_master.app.PseudoPrinterProxy#59f95c5d Before print2
de.scrum_master.app.PseudoPrinterProxy#59f95c5d print2
See? There is always the same object ID, which is no surprise. Self-invocation for your "proxy" (which is not really a proxy but a statically compiled subclass) works due to polymorphism. This is taken care of by the Java compiler.
How it really works
Now please remember we are talking about dynamic proxies here, i.e. subclasses and objects created during runtime:
JDK proxies work for classes implementing interfaces, which means that classes implementing those interfaces are being created during runtime. In this case there is no superclass anyway, which also explains why it only works for public methods: interfaces only have public methods.
CGLIB proxies also work for classes not implementing any interfaces and thus also work for protected and package-scoped methods (not private ones though because you cannot override those, thus the term private).
The crucial point, though, is that in both of the above cases the original object already (and still) exists when the proxies are created, thus there is no such thing as polymorphism. The situation is that we have a dynamically created proxy object delegating to the original object, i.e. we have two objects: a proxy and a delegate.
I want to illustrate it like this:
package de.scrum_master.app;
public class DelegatingPrinterProxy extends DummyPrinter {
DummyPrinter delegate;
public DelegatingPrinterProxy(DummyPrinter delegate) {
this.delegate = delegate;
}
#Override
public void print1() {
System.out.println(this + " Before print1");
delegate.print1();
}
#Override
public void print2() {
System.out.println(this + " Before print2");
delegate.print2();
}
#Override
public void printBoth() {
System.out.println(this + " Before print both");
delegate.printBoth();
}
public static void main(String[] args) {
new DelegatingPrinterProxy(new DummyPrinter()).printBoth();
}
}
See the difference? Consequently the console log changes to:
de.scrum_master.app.DelegatingPrinterProxy#59f95c5d Before print both
de.scrum_master.app.DummyPrinter#5c8da962 print1
de.scrum_master.app.DummyPrinter#5c8da962 print2
This is the behaviour you see with Spring AOP or other parts of Spring using dynamic proxies or even non-Spring applications using JDK or CGLIB proxies in general.
Is this a feature or a limitation? I as an AspectJ (not Spring AOP) user think it is a limitation. Maybe someone else might think it is a feature because due to the way proxy usage is implemented in Spring you can in principle (un-)register aspect advices or interceptors dynamically during runtime, i.e. you have one proxy per original object (delegate), but for each proxy there is a dynamic list of interceptors called before and/or after calling the delegate's original method. This can be a nice thing in very dynamic environments. I have no idea how often you might want to use that. But in AspectJ you also have the if() pointcut designator with which you can determine during runtime whether to apply certain advices (AOP language for interceptors) or not.
Solutions
What you can do in order to solve the problem is:
Switch to native AspectJ, using load-time weaving as described in the Spring manual. Alternatively, you can also use compile-time weaving, e.g. via AspectJ Maven plugin.
If you want to stick with Spring AOP, you need to make your bean proxy-aware, i.e. indirectly also AOP-aware, which is less than ideal from a design point of view. I do not recommend it, but it is easy enough to implement: Simply self-inject a reference to the component, e.g. #Autowired MyComponent INSTANCE and then always call methods using that bean instance: INSTANCE.internalMethod(). This way, all calls will go through proxies and Spring AOP aspects get triggered.
#Dolphin
It is late reply but maybe this text will help you: Spring AOP and self-invocation.
In short, the link leads you to a simple example of why running code from another class will work but from "self" it won't.
Notice looking at the example from the link that when you run code from another class you are asking Spring to inject the bean. And Spring sees that in the bean you are asking for a cache, it creates at runtime proxy for that bean.
On the other hand, when you do the same in the "self" class, you create a compile time method call and Spring won't do anything about it.
Question:
Is it possible to access elements annotated with a #Target(ElementType.TYPE_USE) annotation via an annotation processor?
Is it possible to access the annotated type bounds via an annotation processor?
Links to related documentation I missed are highly appreciated.
Context:
The annotation:
#Target(ElementType.TYPE_USE)
#Retention(RetentionPolicy.SOURCE)
public #interface TypeUseAnno {}
An example class:
public class SomeClass extends HashMap<#TypeUseAnno String, String> {}
The processor:
#SupportedSourceVersion(SourceVersion.RELEASE_8)
#SupportedAnnotationTypes("base.annotations.TypeUseAnno")
public class Processor extends AbstractProcessor {
#Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
this.processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "Initialized.");
}
#Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
this.processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "Invoked.");
for (TypeElement annotation : annotations) {
this.processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "" + roundEnv.getElementsAnnotatedWith(annotation));
}
return true;
}
}
Compiling the above SomeClass with Processor on the classpath will show the "Intialized" message but the process(...) method is never invoked.
Adding another annotation to the processor with #Target(ElementType.PARAMETER) works fine when the annotation is present on a method parameter. If the method parameter is annotated with #TypeUseAnno the process will again ignore the element.
The TYPE_USE annotations are a bit tricky, because the compiler treats them differently, than the "old usage" annotations.
So as you correctly observed, they are not passed to annotation processor, and your process() method will never receive them.
So how to use them at compilation time?
In Java 8, where these annotations got introduced, there was also introduced new way to attach to java compilation. You can now attach listener to compilation tasks, and trigger your own traversal of the source code. So your task to access the annotation splits into two.
Hook to the compiler.
Implement your analyzer.
Ad 1.
There are 2 options to hook on the compiler in Java 8:
Using new compiler plugin API.
Using annotation processor.
I haven't used option #1 much, because it needs to be explicitely specified as javac parameter. So I'll describe option #1:
You have to attach TaskListener to the propper compilation phase. There are various phases. Following one is the only one, during which you have accessible syntax tree representing full source code including method bodies (remember, that TYPE_USE annotations can be used even on local variable declarations.
#SupportedSourceVersion(SourceVersion.RELEASE_8)
public class EndProcessor extends AbstractProcessor {
#Override
public synchronized void init(ProcessingEnvironment env) {
super.init(env);
Trees trees = Trees.instance(env);
JavacTask.instance(env).addTaskListener(new TaskListener() {
#Override
public void started(TaskEvent taskEvent) {
// Nothing to do on task started event.
}
#Override
public void finished(TaskEvent taskEvent) {
if(taskEvent.getKind() == ANALYZE) {
new MyTreeScanner(trees).scan(taskEvent.getCompilationUnit(), null);
}
}
});
}
#Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
// We don't care about this method, as it will never be invoked for our annotation.
return false;
}
}
Ad 2.
Now the MyTreeScanner can scan the full source code, and find the annotations. That applies no matter if you used the Plugin or AnnotationProcessor approach. This is still tricky. You have to implement the TreeScanner, or typically extend the TreePathScanner.
This represents a visitor pattern, where you have to properly analyze, which elements are of your interest to be visited.
Let's give simple example, that can somehow react on local variable declaration (give me 5 minutes):
class MyTreeScanner extends TreePathScanner<Void, Void> {
private final Trees trees;
public MyTreeScanner(Trees trees) {
this.trees = trees;
}
#Override
public Void visitVariable(VariableTree tree, Void aVoid) {
super.visitVariable(variableTree, aVoid);
// This method might be invoked in case of
// 1. method field definition
// 2. method parameter
// 3. local variable declaration
// Therefore you have to filter out somehow what you don't need.
if(tree.getKind() == Tree.Kind.VARIABLE) {
Element variable = trees.getElement(trees.getPath(getCurrentPath().getCompilationUnit(), tree));
MyUseAnnotation annotation = variable.getAnnotation(MyUseAnnotation.class);
// Here you have your annotation.
// You can process it now.
}
return aVoid;
}
}
This is very brief introduction. For real examples you can have a look at following project source code:
https://github.com/c0stra/fluent-api-end-check/tree/master/src/main/java/fluent/api/processors
It's also very important to have good tests while developing such features, so you can debug, reverse engineer and solve all the tricky issues you'll face in this area ;)
For that you can also get inspired here:
https://github.com/c0stra/fluent-api-end-check/blob/master/src/test/java/fluent/api/EndProcessorTest.java
Maybe my last remark, as the annotations are really used differently by the javac, there are some limitations. E.g. it's not suitable for triggering java code generation, because the compiler doesn't pick files created during this phase for further compilation.
Let's say I define a custom annotation called #Unsafe.
I'd like to provide an annotation processor which will detect references to methods annotated with #Unsafe and print a warning.
For example, given this code ...
public class Foo {
#Unsafe
public void doSomething() { ... }
}
public class Bar {
public static void main(String[] args) {
new Foo().doSomething();
}
}
... I want the compiler to print something like:
WARN > Bar.java, line 3 : Call to Unsafe API - Foo.doSomething()
It is very similar in spirit to #Deprecated, but my annotation is communicating something different, so I can't use #Deprecated directly. Is there a way to achieve this with an annotation processor? The annotation processor API seems to be more focused on the entities applying the annotations (Foo.java in my example) than entities which reference annotated members.
This question provides a technique to achieve it as a separate build step using ASM. But I'm wondering if I can do it in a more natural way with javac & annotation processing?
I think I could have technically achieved my goal using the response from #mernst, so I appreciate the suggestion. However, I found another route that worked better for me as I'm working on a commercial product and cannot incoporate the Checker Framework (its GPL license is incompatible with ours).
In my solution, I use my own "standard" java annotation processor to build a listing of all the methods annotated with #Unsafe.
Then, I developed a javac plugin. The Plugin API makes it easy to find every invocation of any method in the AST. By using some tips from this question, I was able to determine the class and method name from the MethodInvocationTree AST node. Then I compare those method invocations with the earlier "listing" I created containing methods annotated with #Unsafe and issue warnings where required.
Here is an abbreviated version of my javac Plugin.
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.util.JavacTask;
import com.sun.source.util.Plugin;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskEvent.Kind;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeInfo;
import com.sun.source.util.TaskListener;
import com.sun.source.util.TreeScanner;
public class UnsafePlugin implements Plugin, TaskListener {
#Override
public String getName() {
return "UnsafePlugin";
}
#Override
public void init(JavacTask task, String... args) {
task.addTaskListener(this);
}
#Override
public void finished(TaskEvent taskEvt) {
if (taskEvt.getKind() == Kind.ANALYZE) {
taskEvt.getCompilationUnit().accept(new TreeScanner<Void, Void>() {
#Override
public Void visitMethodInvocation(MethodInvocationTree methodInv, Void v) {
Element method = TreeInfo.symbol((JCTree) methodInv.getMethodSelect());
TypeElement invokedClass = (TypeElement) method.getEnclosingElement();
String className = invokedClass.toString();
String methodName = methodInv.getMethodSelect().toString().replaceAll(".*\\.", "");
System.out.println("Method Invocation: " + className + " : " + methodName);
return super.visitMethodInvocation(methodInv, v);
}
}, null);
}
}
#Override
public void started(TaskEvent taskEvt) {
}
}
Note - in order for the javac plugin to be invoked, you must provide arguments on the command line:
javac -processorpath build/unsafe-plugin.jar -Xplugin:UnsafePlugin
Also, you must have a file META-INF/services/com.sun.source.util.Plugin in unsafe-plugin.jar containing the fully qualified name of the plugin:
com.unsafetest.javac.UnsafePlugin
Yes, this is possible using annotation processing.
One complication is that a standard annotation processor does not descend into method bodies (it only examines the method declaration). You want an annotation processor that examines every line of code.
The Checker Framework is designed to build such annotation processors. You just need to define a callback that, given a method call and issues a javac warning if the call is not acceptable. (In your case, it's simply whether the method's declaration has an #Unsafe annotation.) The Checker Framework runs that callback on every method call in the program.
The AbstractProcessor below processes greghmerrill's #Unsafe annotation and emits warnings on method calls to #Unsafe annotated methods.
It is a slight modification of greghmerrills own answer, which was great, but I had some problems getting my IDEs incremental compiler (I am using Netbeans) to detect the warnings/errors etc emitted from the plugin - only those I printed from the processor was shown, though the behaviour was as expected when I ran 'mvn clean compile' ( I am using Maven). Whether this is due to some problem from my hand, or a points to difference between Plugins and AbstractProcessors/the phases of the compilation process, I do not know.
Anyway:
package com.hervian.annotationutils.target;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.util.*;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeInfo;
import java.util.Set;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.tools.Diagnostic;
#SupportedAnnotationTypes({"com.hervian.annotationutils.target.Unsafe"})
#SupportedSourceVersion(SourceVersion.RELEASE_8)
public class UnsafeAnnotationProcessor extends AbstractProcessor implements TaskListener {
Trees trees;
#Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
trees = Trees.instance(processingEnv);
JavacTask.instance(processingEnv).setTaskListener(this);
}
#Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
//Process #Unsafe annotated methods if needed
return true;
}
#Override public void finished(TaskEvent taskEvt) {
if (taskEvt.getKind() == TaskEvent.Kind.ANALYZE) {
taskEvt.getCompilationUnit().accept(new TreeScanner<Void, Void>() {
#Override
public Void visitMethodInvocation(MethodInvocationTree methodInv, Void v) {
Element method = TreeInfo.symbol((JCTree) methodInv.getMethodSelect());
Unsafe unsafe = method.getAnnotation(Unsafe.class);
if (unsafe != null) {
JCTree jcTree = (JCTree) methodInv.getMethodSelect();
trees.printMessage(Diagnostic.Kind.WARNING, "Call to unsafe method.", jcTree, taskEvt.getCompilationUnit());
}
return super.visitMethodInvocation(methodInv, v);
}
}, null);
}
}
#Override public void started(TaskEvent taskEvt) { } }
When using the annotation and making calls to the annotated method it will look like this:
One needs to remember to add the fully qualified class name of the annotation processor to a META-INF/service file named javax.annotation.processing.Processor. This makes it available to the ServiceLoader framework.
Maven users having trouble with the com.sun** imports may find this answer from AnimeshSharma helpful.
I keep my annotation + annotation processor in a separate project. I had to disable annotation processing by adding the following to the pom:
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgument>-proc:none</compilerArgument>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
Using the annotation and having the processor do its work was simple: In my other project (the one where the screenshot of method foo() is from) I simply added a dependency to the project containing the annotation and processor.
Lastly it should be mentioned that I am new to AbstractProcessors and TaskListeners. I do, fx, not have an overview of the performance or robustness of the code. The goal was simply to "get it to work" and provide a stub for similar projects.
I have a library class with a package private method. Directly overriding this method by a subclass is no option. Is there any way, no matter how ugly, to execute own code when this package private method is called from inside the library, e.g. using AspectJ?
Here is a simplified example of the class (the packagePrivateMethod() actually is not invoked directly, but from native code):
public LibClass {
public LibClass() {
...
packagePrivateMethod();
...
}
void packagePrivateMethod() {
// <-- here I want to execute additional code
...
}
}
You could use a rather heavyweight approach.
Write a small Java agent SO post about that topic.
Use the provided Instrumentation interface to intercept the class loading
Use a byte code modification library (e.g. ASM or Java Assist (only Java 6 !) ) to instrument the byte code (e.g. to replace the method call with whatever you really want to do.
This would work as you can modify the byte code of everything, but it requires you to modify that byte code before it is executed.
Of course you can do that also statically by just modifying the class file, replacing the existing byte code with the byte code you create in step 3 above.
If you do not want / cannot statically replace the byte code of the class, you'll have to do the modification of the bytecode at runtime. For the using a Java agent is a good and solid idea.
Since this is all rather abstract until now, I have added an example which will intercept the loading of your library class, inject a method call in a package private method. When the main method executes, you can see from the output, that the injected method is called directly before the library classes' code. If you add return; as the injected code, you can also prevent the execution of that method alltogether.
So here is the code of an example to your problem solved with Java 6 and JavaAssist. If you want to go along that path and use something newer like Java 7, the you just have to replace the byte code manipulation with ASM. This is a little bit less readable, but also not exactly rocket science.
The main class:
package com.aop.example;
public class Main {
public static void main(String[] args) {
System.out.println("Main starts!");
LibClass libClass = new LibClass();
System.out.println("Main finished!");
}
}
Your LibClass:
package com.aop.example;
public class LibClass {
public LibClass() {
packagePrivateMethod();
}
void packagePrivateMethod() {
// <-- here I want to execute additional code
System.out.println("In packagePrivateMethod");
}
}
The Agent:
package com.aop.agent;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.LoaderClassPath;
import javassist.NotFoundException;
public class Agent {
public static void premain(String agentArgs, Instrumentation instr) {
System.out.println("Agent starts!");
instr.addTransformer(new ClassFileTransformer() {
#Override
public byte[] transform(ClassLoader classLoader, String className, Class<?> arg2, ProtectionDomain arg3,
byte[] bytes)
throws IllegalClassFormatException {
System.out.println("Before loading class " + className);
final String TARGET_CLASS = "com/aop/example/LibClass";
if (!className.equals(TARGET_CLASS)) {
return null;
}
LoaderClassPath path = new LoaderClassPath(classLoader);
ClassPool pool = new ClassPool();
pool.appendSystemPath();
pool.appendClassPath(path);
try {
CtClass targetClass = pool.get(TARGET_CLASS.replace('/', '.'));
System.out.println("Enhancing class " + targetClass.getName());
CtMethod[] methods = targetClass.getDeclaredMethods();
for (CtMethod method : methods) {
if (!method.getName().contains("packagePrivateMethod")) {
continue;
}
System.out.println("Enhancing method " + method.getSignature());
String myMethodInvocation = "com.aop.agent.Agent.myMethodInvocation();";
method.insertBefore(myMethodInvocation);
}
System.out.println("Enhanced bytecode");
return targetClass.toBytecode();
}
catch (CannotCompileException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
catch (NotFoundException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
});
}
public static void myMethodInvocation() {
System.out.println("<<<My injected code>>>!");
}
}
The command for running the example (you have to put a agent in a jar with the manifest having an attribute Premain-Class: com.aop.agent.Agent:
%JAVA_HOME%\bin\java -cp .;..\javassist-3.12.1.GA.jar -javaagent:..\..\agent.jar com.aop.example.Main
The output of this example running a command like this:
Agent starts!
Before loading class com/aop/example/Main
Main starts!
Before loading class com/aop/example/LibClass
Enhancing class com.aop.example.LibClass
Enhancing method ()V
Enhanced bytecode
<<<My injected code>>>!
In packagePrivateMethod
Main finished!
Before loading class java/lang/Shutdown
Before loading class java/lang/Shutdown$Lock
You can you Mockito or similar mock library to mock a package private method. Example:
// declared in a package
public class Foo {
String foo(){
return "hey!";
}
}
#Test
public void testFoo() throws Exception {
Foo foo = Mockito.spy(new Foo());
Assert.assertEquals("hey!", foo.foo());
Mockito.when(foo.foo()).thenReturn("bar!");
Assert.assertEquals("bar!", foo.foo());
}
Can you add Spring to your project?
It might be possible to use a ProxyFactory - see another SO post
Using the ProxyFactory, you can add an advice for a class instance and delegate the method execution to another class (which does packagePrivateMethod() and/or replaces it with the code you want).
Since the library is not spring-managed, you might have to use load-time weaving with spring: ltw xml & examples
use the decorator pattern. Its specifically designed for this situation. If you need more details then ping me back else check this
Or you can also use reflections or a byte code manipulation mechanism to create your type dynamically at runtime.
Another idea: create a new class with the same name in the same package.
Say you want to replace LibraryClass in the below project:
Project structure:
- library.jar (contains com.example.LibraryClass)
- src
- com
- mycompany
- MyClass.java
Just create the package and file with the same name.
Project structure:
- library.jar (contains com.example.LibraryClass)
- src
- com
- mycompany
- MyClass.java
- example
- LibraryClass.java <- create this package and file
This relies on the class loader picking up your file instead of the library's file, but if you are just trying to get a hack working for testing, it is worth a shot. I'm not sure how the class loader decides which file to load, so this may not work in all environments.
If you don't have the source code for LibraryClass, just copy the decompiled code, and make your changes.
For the project where I needed this ability, it was just some test prototyping code... I didn't need anything production quality, or to work in all environments.
I am trying to migrate a small project, replacing some factories with Guice (it is my first Guice trial). However, I am stuck when trying to inject generics. I managed to extract a small toy example with two classes and a module:
import com.google.inject.Inject;
public class Console<T> {
private final StringOutput<T> out;
#Inject
public Console(StringOutput<T> out) {
this.out = out;
}
public void print(T t) {
System.out.println(out.converter(t));
}
}
public class StringOutput<T> {
public String converter(T t) {
return t.toString();
}
}
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.TypeLiteral;
public class MyModule extends AbstractModule {
#Override
protected void configure() {
bind(StringOutput.class);
bind(Console.class);
}
public static void main(String[] args) {
Injector injector = Guice.createInjector( new MyModule() );
StringOutput<Integer> out = injector.getInstance(StringOutput.class);
System.out.println( out.converter(12) );
Console<Double> cons = injector.getInstance(Console.class);
cons.print(123.0);
}
}
When I run this example, all I got is:
Exception in thread "main" com.google.inject.CreationException: Guice creation errors:
1) playground.StringOutput<T> cannot be used as a key; It is not fully specified.
at playground.MyModule.configure(MyModule.java:15)
1 error
at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:354)
at com.google.inject.InjectorBuilder.initializeStatically(InjectorBuilder.java:152)
at com.google.inject.InjectorBuilder.build(InjectorBuilder.java:105)
at com.google.inject.Guice.createInjector(Guice.java:92)
I tried looking for the error message, but without finding any useful hints. Further on the Guice FAQ I stumble upon a question about how to inject generics. I tried to add the following binding in the configure method:
bind(new TypeLiteral<StringOutput<Double>>() {}).toInstance(new StringOutput<Double>());
But without success (same error message).
Can someone explain me the error message and provide me some tips ? Thanks.
I think the specific issue you're seeing is probably because of the bind(Console.class) statement. It should use a TypeLiteral as well. Or, you could just bind neither of those and JIT bindings will take care of it for you since both of the types involved here are concrete classes.
Additionally, you should retrieve the Console with:
Console<Double> cons =
injector.getInstance(Key.get(new TypeLiteral<Console<Double>>(){}));
Edit: You don't need to bind to an instance just because you're using a TypeLiteral. You can just do:
bind(new TypeLiteral<Console<Double>>(){});
Of course, like I said above you could just skip that in this case and retrieve the Console from the injector using a Key based on the TypeLiteral and the binding would be implicit.