As we all know, we can automagicaly generate code using custom annotations and Java annotation processors as guys at project Lombook do. But can we remove the annotated code from compiled sources ?
I've tried searching the web for it, but only things that appear are "generate your code" topics and tutorials on "how to generate server with one annotation".
It came to my mind while I was searching for ways to "compile out" debug messages from prod app. I can understand, that having the debug/test and production code is not a good practice, but sometimes it is needed to keep things simple. I think of few scenarios for this:
make debug only, laggy code used in developer-only version of code that can have different levels of importance for example:
#Debug(0) void cpuLightFunction(){}
#Debug(100) void cpuHeavyFunction(){}
void doWork(){
cpuLightFunction();
cpuHeavyFunction();
}
In annotation processing step we could use some option to define max level of #Debug annotations that would be compiled. Any usage of #Debug with higher level would produce error or warning in the same way as #Deprecated
platform specyfic code versions - create custom #Platform(ANDROID) void doSomething() and #Plaform(IOS) void doSomething functions that run only on given plaform to get rid of polymorphic void doSomething(AndroidPlatform) or void doSomethingAndroid() code
have parts of code that are conditionally compiled:
#Optional("NetworkStub")
class NetworkStub{
// ...
}
#Optional("PaymentStub")
class PaymentStub{
// ...
}
and only use compiler/annotation processor options to enable/disable parts of the code, for example -Aoptional="NetworkStub" that would only compile code related to NetworkStub in the code and remove all code touching PaymentStub.
You can do this by writing an annotation processor that traverses and modifies the program's AST (abstract syntax tree) during compilation, before code generation.
That is how Project Lombok works.
This question is a near-duplicate of How to write a Java annotation processor?, but the accepted answer to that question says it's impossible, which is factually wrong.
Related
Is it possible that use self defined Annotation to classify java class into different product function ? (Following are my thoughts)
If not, are there any other method to achieve the same purpose in Android project?
Step1: use self defined annotation to make clear java class's function
#SelfDefinedAnnotation( "product-function-a" )
class MyClass {
void func() {
//do something
}
}
Step2: during building period, generate a mapping file like this
MyClass -> product-function-a
YourClass -> product-function-b
I'm not sure about android (never worked with it), but in pure java its possible for sure.
You should define an annotation with retention policy SOURCE and since you're talking about build time, define an annotation processor. This is something that is "hooked" into the compilation process and allows creating such a mapping (I assume you want to store it in some kind of file, maybe *.properties file, or even generate a java source code with these definitions.
The annotation processor is broad topic, there are many ways to register them, so it pretty much depends on how do you build your stuff exactly, but its a general direction.
Please check out this tutorial it talks about annotation processors, the ways to register them, to associate with your custom annotation and so forth.
One suggestion though, if you're about to generate Java Source class and not just a properties file, this tutorial goes "low level" and tries to prepare the syntax by itself, I suggest using a much nicer (IMO) Java Poet library that will help to generate a proper java code
There is a Java application and I have no permission to alter the Java code apart from annotating classes or methods (with custom or existing annotations).
Using annotations and annotations only I have to invoke code which means that every time an instance of an annotated class is created or an annotated method is called, some extra Java code must be executed (e.g a call to a REST Webservice). So my question is: how can I do this?
In order to prevent answers that I have already checked I will give you some solutions that seem to work but are not satisfying enough.
Aspect Oriented Programming (e.g AspectJ) can do this (execute code before and after the call of an annotated method) but I don't really want the runtime overhead.
Use the solution provided here which actually uses reflection. This is exactly what I need only that it alters the initial code further than just annotating and so I cannot use it.
Use annotation processor for source code generation as suggested here by the last answer. However, still this means that I will alter the source code which I don't want.
What I would really like is a way to simply include a Java file that somehow will execute some Java lines every time the annotated element will be triggered.
Why not skip annotations completely and use byteman to inject code at runtime into the entry points of your code.
I have to agree with the comment above though, that this sort of restriction is ridiculous and should be challenged.
Hoi!
The problem I discovered is pretty simple to understand but I can't find a solution.
First let me provide this little snippet.
#Deployment
public static Archive<?> createDeployableArchive () {
JavaArchive jar = ShrinkWrap.create(JavaArchive.class, "whoCares.jar");
// enable CDI
jar.addAsManifestResource(EmptyAsset.INSTANCE, ArchivePaths.create("beans.xml");
// Some persistence
jar.addAsManifestResource("test-persistence.xml", "persistence.xml");
// Now the interisting part (simplified):
jar.addClass(RegistrationService.class) // This one should be tested
.addClass(RegistrationException.class) // Will be thrown on error.
.addClass(UserDAO.class) // Used by RegService
.addClass(User.class) // JPA Entity
// ...
// ... This scenario goes without interfaces, inheritance, DTOs, different
// ... types of exceptions for different problem types... That's why the list
// ... is so concise.
// ...
.addClass(RegServiceIntegrationTest.class); // Test class must be included
return jar;
}
Every time you want to test a certain use case, for example registerUser, with arquillian you will have to collect all classes your registration process depends on and put them together in a deployable archive.
Doing this manually will cost time and produce problems and errors, for sure! There are several weak points:
Collecting: Think of a long process with many sub services, exceptions, interfaces, super classes, utility stuff and so on. You will walk over the complete flow to find them all. Honestly, that's a repetitious long term job that will be a pain the... eyes. I had to do it just a few times before I decided to rather start yelling.
Keeping your tests up to date: Imagine you involve a new sub service to your registration chain. You will have to update those damn dependencies and if something goes wrong when you run your integration tests at the end of the day there will be fun digging through sometimes incomplete exception messages (incomplete cause you only know something is missing at some point but not what exactly). If you're lucky a ClassNotFoundException occurs. One change could of course easily affect multiple tests:
1. Let UserDao throw some new fancy runtime exception.
2. Waste your life time.
Problems with adding packages: Adding packages is provided by Shrinkwrap but using it would be a bad Idea. Sometimes, after a long day, you feel lazy and just add complete packages but can you be absolutely sure every class will remain in the same package forever? Another problem is that the term "micro deployment" implies a need for compactness. Whole packages introduce overhead, okay I guess that's the smallest problem here.
How to solve this (Just unqualified thoughts)?
It is kind of banal that all required information already is available in the source code.
The best solution would be something like this:
#Deployment
public static Archive<?> createDeployableArchive () {
JavaArchive jar = ShrinkWrap.create(JavaArchive.class, "whoCares.jar");
// enable CDI
jar.addAsManifestResource(EmptyAsset.INSTANCE, ArchivePaths.create("beans.xml");
// Some persistence
jar.addAsManifestResource("test-persistence.xml", "persistence.xml");
Class<?>[] involved;
involved = Tool.findInvolvedClasses("RegistrationService.java", "registerUser");
jar.addClasses(involved);
return jar;
}
I don't think one can achieve this using reflection as it's necessary to know the exact "flow".
I bet there is a cool tool out there that could be put to an unintended use. There might of course be other ways. Does somebody have an idea? Thanks!
You could try out the Arquillian integration in JBoss Tools. You'l find some information on how to use it, in this GitHub repo; see the README. The screencasts linked there might be useful.
To get started with JBoss Tools, you can install it into an existing Eclipse Kepler (e4.3) or above installation via the JBT update site, with these instructions.
Note, this is considered experimental at the moment so it is not included in JBoss Developer Studio (the distribution that packages Eclipse and some plugins), and is available only in the community bits, i.e. JBoss Tools. We'd appreciate if you file any issues you encounter (or any new feature requests) in the JBoss Tools JIRA (please use the testing-tools component).
Does anybody have some kind of "code style" annotations in the project, ex: #OverEngineered for over-complexed code or #Duplicated... etc.
Ideally I'd subclass #Deprecated for that (#OverEngineered extends #Deprecated) to get the IDE highlight it, but java annotations are not inherited.
So I wonder if there is some workaround to get the IDE to highlight such code-style custom annotations as deprecated? Or is this the wrong way or wrong task in general?
You could write a family of these annotations, and then use them alongside #Deprecated. The latter gets you the warnings, the former supply the details to human readers. You could write a Checkstyle rule to require that every deprecated thing has an explanatory annotation, and/or that every explanation accompanies a deprecation.
Rather than writing several annotations, though, i'd write one, which takes an explanatory label as a parameter. I'd call it #BecauseItIs. So:
#Deprecated #BecauseItIs("overengineered")
public void calculateSumOfTwoIntegersUsingSurfaceIntegrals(int a, int b) {
The workaround would be implemented with a plugin you develop for Eclipse. I would say, however, nothing is more semantically as a good written comment in the code.
After all it depends on the purpose. But I think a good comment is better than a plugin which anyone has to install.
It's not clear to me if you have another goal besides calling attention to the spot in the IDE. You mention #Deprecated which also shows up in the Javadoc, IDE documentation popups, and compiler output.
For simply the IDE highlighting without the other possibilities, you could leverage the FIXME / TODO sorts of comment tags that most IDEs support (at least those I've used). Just add your own tags for OVERENGINEERED: this is too ... etc.
Eclipse allows you to also specify if you want case matched, so it could be OverEngineered:
With generated Java source code, like
code generated with Hibernate tools
code generated with JAXB schema binding (xjc)
code generated with WDSL2Java (cxf)
all generated classes are "value object" types, without business logic. And if I add methods to the generated source code, I will loose these methods if I repeat the source code generation.
Do these Java code generation tools offer ways to "extend" the generated code?
For example,
to override the ToString method (for logging)
to implement the visitor pattern (for data analysis / validation)
For JAXB, see Adding Behaviours.
Basically, you configure JAXB to return a custom instance of the object you'd normally expect. In the below example you create a new object PersonEx which extends the JAXB object Person. This mechanism works well in that you're deriving from the generated classes, and not altering the JAXB classes or schemas at all.
package org.acme.foo.impl;
class PersonEx extends Person {
#Override
public void setName(String name) {
if(name.length()<3) throw new IllegalArgumentException();
super.setName(name);
}
}
#XmlRegistry
class ObjectFactoryEx extends ObjectFactory {
#Override
Person createPerson() {
return new PersonEx();
}
}
Note that the #Override directive is important in case your JAXB object changes - it will prevent your customisation becoming orphaned.
As for Hibernate you may tweak the template files used in code generation to change their behaviour. If you want to tweak the HIbernate Tools you can edit, for example: dao/daohome.ftl
You may even add fields to the "toString()" output editing the .hbm.xml files
...
<property name="note" type="string">
<meta attribute="use-in-tostring">true</meta>
<column name="note" />
</property>
...
Both for logging and validation you may consider using AOP with AspectJ (I don't recommend messing with the generated code, since you might want to build that from scratch many times over).
First I would reiterate that modification of generated code has many problems associated with it and that, where possible it should be avoided. That said sometimes this is impractical to avoid or more effort than just dealing with the changes when the code is regenerated.
Sadly java doesn't support the concept of partial classes that c# has. These are precisely to solve this sort of problem.
You should see if your code generation tools support some form of meaningful comments which delimit regions added by yourself in the class (this is unlikely and won't help if you are modifying the code rather than adding to it)
You best option if you really wish to do this is to generate the files initially but check them into a version control repository immediately.
Then make your changes, check that in.
Next time you rerun the tools and let them overwrite the existing files you can diff against your source controlled ones and merge the changes back in (most trivial changes like addition of new columns/tables will be little effort.
This will not help you as much if the code generator suddenly generates radically different code (say a new version) but in those cases any code you added which wasn't simply additional convenience methods relying on data/methods already exposed publicly) will have problems no matter how it is mixed into the class. The version control system does still help however since it also records the original changes so you can see what you had added previously and what, one would assume, you need to recreate in the new style.
It is not a good idea to edit generated code files, either by editing the files them selves or by subclassing. Whatever you do, be sure to leave the signature created by the tool intact, so that it will be possible to understand in the future that the file was auto-generated.
I recommend that you research the command options of the tools to see if they allow you some flexibility. Some tools can generate abstract classes or interfaces instead of concrete classes. If this is not possible, create a domain object that includes the autogenerated object as a member variable.
The way I have used Hibernate is to generate base classes that I then extend. I add all my business logic (if any) to these subclasses. I quite often also end up changing the FreeMarker templates used by Hibernate to further customize the generated classes.
The AOP citation is a good one. I'll add Spring, which has very nice AOP features built in.
Have a look at
http://code.google.com/p/jaxb-method-inserter/
Its a small plugin for JAXB I wrote, Its quite simple to uses. Hope it help