Java 6 annotation processor with Filer.createClassFile() implementation - java

I am trying to write an annotation processor in Java 6. I wrote a sample implementation, which creates a new source file in the process method and it works fine.
#SupportedAnnotationTypes(value = {"*"})
#SupportedSourceVersion(SourceVersion.RELEASE_6)
public class BrownfieldAnnotationProcessor extends AbstractProcessor{
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
try {
JavaFileObject f = processingEnv.getFiler().
createSourceFile("in.test.ExtraClass");
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
"Creating " + f.toUri());
Writer w = f.openWriter();
try {
PrintWriter pw = new PrintWriter(w);
pw.println("package in.test;");
pw.println("public class ExtraClass implements TestInterface{");
pw.println(" public void print() {");
pw.println(" System.out.println(\"Hello boss!\");");
pw.println(" }");
pw.println("}");
pw.flush();
} finally {
w.close();
}
} catch (IOException x) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
x.toString());
}
return true;
}
}
But in my case, i do not want another java file to be created and instead i want to generate a class file directly. How to create a class file? Should i use a dynamic compiler to compile this source in string to create the class? In that scenario, i can directly store the class files in the file system. What is the usage of
processingEnv.getFiler().createClassFile()
method?
I tried googling around, but could never find an example using this method.

I see only few reasons for creating class files instead of source code files. Actually this are the same reasons why you would ever need to create bytecode by hand in any situation.
You absolutly need control over the bytecode (maybe for 'optimization' or testing purposes)
You need to use features that are available in bytcode but not in the Java language
I think you rarely need to do any of the above. If this is really what you want to do, you should know a lot about the format of class files and bytecode of course. You would basically be creating some kind of compiler at this point.
You could argue that by shipping precompiled classes, or by generating bytcode directly, you can skip a step in the built process and the user's program will compiler faster. That may be true true but I'm sure the speed will be neglectable. It would be easier to just work with source code and pass it to the filer for compilation.
Should i use a dynamic compiler to compile this source in string to create the class?
No, I see no advantage here. If you create a source code file with the filer it will be compiled automatically. You only need to do this if your source code is not Java but some other language that you want to compile for the JVM.

Related

Is that possible implement the same code but only enabled when imported the jar

Is that possible implement the same code but only enabled when adding a dependency to SpringBoot project?
If possible, how to achieve it?
I want to implement the code like this:
DoSomethingUtil doSomethingUtil = new DoSomethingUtil();
doSomethingUtil.send("API URL", "System A", "Hello");
It would do nothing when project didn't add the implement of the DoSomethingUtil.java.
After adding to pom.xml that which would implement the DoSomethingUtil.java, it would really do something.
Given that you don't need to know about DoSomethingUtil anywhere else in your code, you can run something on it only if it's present in your classpath (without importing it) if you use reflection all the way:
try {
Class<?> dsuClass = Class.forName("do.something.util.DoSomethingUtil");
Object dsuInstance = dsyClass.getConstructor().newInstance();
Method sendMethod = dsuClass.getDecaredMethod("send", String.class, String.class, String.class);
sendMethod.invoke(dsuInstance, "API URL", "System A", "Hello");
} catch (Exception ignored) {}
You may want to revisit the poor error handling above to distinguish (at least) between class not being present in the classpath and send() method invocation failure.
What you appear to be describing is adding a dependency, not "importing" something.
Will it work?
Sort of. What you could do is overlay the definition of the.pkg.DoSomethingUtil with another version of the.pkg.DoSomethingUtil in a different JAR file. It can work, but it makes your application sensitive to the order of the JARs on the runtime classpath. That makes your application fragile ... to say the least.
You can probably make this work with classic Java if you have full control of the runtime classpath. However:
I'm not sure if it will work with SpringBoot.
If you tried this sort of thing on Android, the APK builder would protest. It treats the scenario of two classes with the same full name as an error.
I think there is a better solution:
Refactor the code so that there is a DoSomethingUtil interface and two classes; e.g. RealDoSomethingUtil and DummyDoSomethingUtil.
Replace new DoSomethingUtil() with a call to a factory method.
Implement the factory method something like this:
private static Class<?> doSomethingClass;
public static synchronized DoSomethingUtil makeDoSomethingUtil() {
if (doSomethingClass == null) {
try {
doSomethingClass = Class.forName("the.pkg.RealDoSomethingUtil");
} catch (Exception ex) {
doSomethingClass = the.pkg.DummyDoSomethingUtil.class;
}
}
return (DoSomethingUtil) (doSomethingClass.newInstance());
}
Put RealDoSomethingUtil into the add-on JAR file, and DoSomethingUtil, RealDoSomethingUtil and the factory method into the main JAR file.
You should probably make the exception handling more selective so that it deals with different classloader errors differently. For example, if RealDoSomethingUtil exists but can't be loaded, you probably should log that ... or maybe let the exception crash the application.
You could also make use of ServiceLoader, but I don't know if it would be simpler ...
The java Service Provide API (SPI) is there to detect wether implementation(s) of an interface exists.
You have a jar with an interface DoSomethingUtil in your application.
Possibly on the class path an implementation jar (MyDoSomethingUtilImpl implements DoSomethingUtil), with an entry in META-INF/services.
You must check whether the interface is implemented.
One could make a fallback implementation.

How to execute scala code using java

I am new to scala. I have a requirement to execute the scala class using java.
My exact requirement is: I need to pass the entire scala class (file) as an argument to the java jar. That jar should read the scala code and execute it. I have searched many sites but did not find the appropriate answer. Is there any way to do the same?
Thank you in Advance.
Besides of your motivation to do that, it is for sure possible (I did it using my IDE - sbt project)
I just made scala class as below:
import com.google.common.base.Objects
class Car(_color: String, _valid: Boolean) {
val color: String = _color
val valid: Boolean = _valid
override def toString = Objects.toStringHelper(this).add("color",color).add("valid", valid).toString
}
After that I made class with main method to test it.
public class Test {
public static void main(String[] args) {
Car test = new Car("test", true);
System.out.println("test = " + test);
}
}
It compiled without any problems and the result was like below:
test = Car{color=test, valid=true}
Scala has its own compiler scalac whereas java uses javac. Since scalac compiles to class file that java can read and assuming that you are only using java libraries in the class then you can load the class in java. So what you need is to call scalac to compile the scala file and then load the generate class file using ClassLoader

Dynamically loading Groovy scripts into app server

I have a Java Spring app running in Tomcat that is meant to perform various processing rules based on incoming files. Because the file types and rules change, I would like to use Groovy to dynamically load new/changed functionality without having to recompile/restart the Java application each time.
Following the "Dynamically loading and running Groovy code inside Java" from the Groovy documentation,
GroovyClassLoader gcl = new GroovyClassLoader();
Class clazz = gcl.parseClass(myStringwithGroovyClassSource, "SomeName.groovy");
Object aScript = clazz.newInstance();
MyInterface myObject = (MyInterface) aScript;
myObject.interfaceMethod();
I created my version of SomeName.groovy that implements MyInterface and modified my Java app to then create an instance of that class as shown above. I know that my Groovy file is being read correctly because if I print out myObject.getClass().toString it shows the correct object type as defined in SomeName.groovy; however, when it gets to point of calling one of the implemented methods (myObject.interfaceMethod()) it doesn't do anything.
I've tested this approach in a Java application outside of Tomcat and it worked so I'm uncertain as to why running this inside of an app server would cause it to break. Also, I've confirmed that groovy-all-2.1.8.jar is included in my project.
Thanks in advance for any information that you can provide that might shed some light on why the dynamic loading might be failing.
Thx.
The form of the parseClass() method that you are using does not look at any external file at all. Instead it treats the first String argument (myStringwithGroovyClassSource in your case) as if it were the text content of a Groovy source file, and the second String argument (the literal "SomeName.groovy" in your case) as if it were the name of that file. This method does not open or parse any ACTUAL file at all.
To make this code work as is you would have to predefine the variable myStringwithGroovyClassSource. The overall effect would look something like this:
def myStringwithGroovyClassSource = """
class SomeName implements MyInterface {
def prop1 = 1, prop2 = 2
def interfaceMethod() { println prop1 }
}
"""
interface MyInterface { def interfaceMethod() }
GroovyClassLoader gcl = new GroovyClassLoader()
Class clazz = gcl.parseClass(myStringwithGroovyClassSource, "SomeName.groovy")
Object aScript = clazz.newInstance()
MyInterface myObject = (MyInterface) aScript
myObject.interfaceMethod()
Now, on the other hand, if, as you say, you already have an external uncompiled Groovy source file named SomeFile.groovy that you wish to bring into your script via the GroovyClassLoader, then you need to change your existing code to something like this:
interface MyInterface { def interfaceMethod() }
GroovyClassLoader gcl = new GroovyClassLoader()
Class clazz = gcl.parseClass("SomeName.groovy" as File)
Object aScript = clazz.newInstance()
MyInterface myObject = (MyInterface) aScript
myObject.interfaceMethod()
If the code in the file is valid-when-compiled, then you should have no trouble getting this to work.

When do we use Static and Dynamic class Loading?

I know the difference between Static class loading and Dynamic class loading.
In general,we always use Static class loading only.Can anyone tell, under which situations we use Dynamic class loading??
Dynamic Class Loading allows the loading of java code that is not known about before a program starts. The Java model loads classes as needed and need not know the name of all classes in a collection before any one of its classes can be loaded and run.
For example :
Depending on user input you want to create only one object and there are hundreds of classes.
Then you don't need load all classes. You can create object at run time by dynamic class loading.
Code:
try {
InputStreamReader in = new InputStreamReader(System.in);
BufferedReader reader = new BufferedReader(in);
System.out.println("Enter Class Name: ");
String whatClass = reader.readLine();
Class exampleClass = Class.forName(whatClass);
Object ob = exampleClass.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
DYNAMIC CLASS LOADING
It allows you to build your applications so that key external dependencies are not compiled into the application source-code.
APPLICATIONS
JDBC
For example, in the JDBC case, it allows you to switch between different driver implementations, and (in theory) different database vendors without changing your source code.
PLUG-INS
Another use-case is when some supplier develops a generic form of an application with extension points that allow customers to "plug in" their own custom classes. The custom classes are typically loaded using Class.forName(...).
FRAMEWORKS AND CONTAINERS
A third use-case is application frameworks and containers which typically use Class.forName(...) under the hood to dynamically load the classes for application-specific beans, servlets, and so on.
OTHERS
A fourth use-case is where the application (or more likely an application library) has modules that are not used in a typical application run. By using Class.forName(...) internally, the application or library can avoid the CPU and memory overhead of loading and initializing large numbers of unwanted classes. (The Sun Swing libraries apparently do this to reduce application startup times, and I'm sure there are other examples.)
Refer Dynamic Class Loading
One common example is trivial JDBC programming. Dynamic classloading is used to load the driver class
If you see any code with Class.forName() then that is the example for dynamic loading
Generally speaking, whenever your program will use classes that aren't necessarily available at compile time. An example would be a plug-in system, where you could create new plug-ins without recompiling the original application.
When you are using reflection and creating new instances. You can always fetch new jar eg. via url and create object from it on runtime.
Most common case in Java are plugins and plugin like libraries like JDBC drivers.
Dynamic loading is a technique for programmatically invoking the functions of a class loader at run time. Let us look at how to load classes dynamically by using Class.forName (String className); method, it is a static method.
The above static method returns the class object associated with the class name. The string className can be supplied dynamically at run time. Once the class is dynamically loaded the class.newInstance () method returns an instance of the loaded class. It is just like creating a class object with no arguments.
A ClassNotFoundException is thrown when an application tries to load in a class through its class name, but no definition for the class with the specified name could be found.
Here is example of dynamic class loading:
import java.util.Scanner;
interface IRobot{
void start();
}
class Robot implements IRobot{
public void start(){
System.out.println("Starting robot...");
}
}
public class Hello{
public static void main(String[] args){
ClassLoader loader = Hello.class.getClassLoader();
try {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter class name to load: ");
String className = scanner.nextLine();
// Load the class dynamically.
Class cls = loader.loadClass(className);
IRobot obj =(IRobot) cls.newInstance();
obj.start();
scanner.close();
} catch (ClassNotFoundException e) {
System.out.println("Class not found");
} catch (Exception ex){
System.out.println(ex.getMessage());
System.out.println("Exception occured.");
}
}
}

Implementing Spring-like package scanning in Android

I'm attempting to implement a package-scanning feature, similar to Spring's component-scan, for the Android framework I'm developing. Basically, I would like to be able to specify a base package, e.g. com.foo.bar and retrieve all Class instances that have a particular annotation. I don't want to have to register every component with my framework as that would defeat the purpose of the auto scanning.
Based on my research, it seems that it's not possible with Java to retrieve resources given a package name using reflection. However, I briefly looked into the Reflections framework, and I'm wondering if there is an Android-compatible equivalent. If not, perhaps there is a slightly less obvious way to accomplish what I want to do.
I looked into the Spring source a bit to see how they achieved this, but I don't think what they are doing would work within the Dalvik runtime.
Update
Currently, the below code has been the best I can do to retrieve all classes that contain a specific annotation, but frankly it's a pretty poor solution. It makes some really unsafe assumptions about the ClassLoader plus it scans (and loads) all application classes.
public Set<Class<?>> getClassesWithAnnotation(Class<? extends Annotation> annotation) {
Set<Class<?>> classes = new HashSet<Class<?>>();
Field dexField = PathClassLoader.class.getDeclaredField("mDexs");
dexField.setAccessible(true);
PathClassLoader classLoader = (PathClassLoader) Thread.currentThread().getContextClassLoader();
DexFile[] dexs = (DexFile[]) dexField.get(classLoader);
for (DexFile dex : dexs) {
Enumeration<String> entries = dex.entries();
while (entries.hasMoreElements()) {
String entry = entries.nextElement();
Class<?> entryClass = dex.loadClass(entry, classLoader);
if (entryClass != null && entryClass.isAnnotationPresent(annotation)) {
classes.add(entryClass);
}
}
}
return classes;
}
I wanted to find all the subclass at runtime.
So I've been looking for android class scanning.
This is my final code from what I gathered in web.
You will get the idea.
public static void findSubClasses(Context context, Class parent) {
ApplicationInfo ai = context.getApplicationInfo();
String classPath = ai.sourceDir;
DexFile dex = null;
try {
dex = new DexFile(classPath);
Enumeration<String> apkClassNames = dex.entries();
while (apkClassNames.hasMoreElements()) {
String className = apkClassNames.nextElement();
try {
Class c = context.getClassLoader().loadClass(className);
if (parent.isAssignableFrom(c)) {
android.util.Log.i("nora", className);
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// android.util.Log.i("nora", className);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
dex.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I share the opinion of Joop Eggen and find his approach a good one. In Android I try to avoid the usual web app features which lead to a long lasting application start. I do not use reflection or package scanning.
But if you want to .... if I understand it correctly you want to have an annotation for a class. Instead of using annotations you could also use marker interfaces (to just have more possibilites).
1) Look at
Annotation: Java custom annotation and dynamic loading
Has an implementation in the question which just answers your question.
Annotation: Scanning Java annotations at runtime
Interface: Find Java classes implementing an interface
Interface: Is something similar to ServiceLoader in Java 1.5?
Interface: How can I get a list of all the implementations of an interface programmatically in Java?
Interface: Since the approach is expensive, maybe the ServiceLoader is a compromise between execution time and comfort, since it loads only the classes given in the services file. On the other hand if only classes with a certain interface are in your package then the ServiceLoader isn't that faster.
2) AndroidAnnotations
I would prefer the way AndroidAnnotations work (maybe an integration in AndroidAnnotations is the preferable way): It automatically adds an extra compilation step that generates source code, using the standard Java Annotation Processing Tool. So instead of runtime scanning you execute code based on the annotations generated during compile time.
I think the Bean/EBean annotation could work for you (only single class): https://github.com/excilys/androidannotations/wiki/Enhance%20custom%20classes
A scan-feature is not available, see this thread
3) Writing your own annotation processor
See APT (Annotation Processing Tool). The idea would be to generate a static function which returns a list of classes which are annotated, so that no class scanning is needed.
A very good ressource is http://javadude.com/articles/annotations/index.html
Take a look at Vogar's ClassPathScanner. It uses it to find test cases on the class path.
EDIT:
I found this issue in the Android issue tracker. It appears that ClassLoader.getResource(String) is 'working as expected', in that it returns null. This is expected because the DalvikVM does not keep the resources around after compiling. There are workarounds listed in the issue, but there may be another way to access the classes you desire.
Use the PackageManager to get a hold of an instance of ApplicationInfo. ApplicationInfo has a public field called sourceDir which is the full path (a String) to the location of the source directory for that application. Create a File from this String, and you should be able to navigate to your package within the source directory. Once there, you can use the method from my original answer to find the classes you are looking for.
String applicationSourceDir =
getPackageManager().getApplicationInfo(androidPackageName, 0).sourceDir;
/EDIT
You should be able to use the ClassLoader.getResource(String) to get a URL to your specific package (the passed in String being the package name you are interested in delimited by path separators rather than periods). With this URL you can then call getFile(), from which you can create a Java File to the package folder. Call packageFile.listFiles() from there, and you have your classes/subpackages.
Be recursive with the subpackages, and with the classes find the Class object using the static Class.forName(String) method.
In your java build process incorporate the class path scanning, generating injection data/code. This could then be ported too to Dalvik. It is even more efficient that dynamic scanning.

Categories