Do plexus annotations work in a maven plugin? - java

I'm working on a custom maven plugin and I'm trying to use the Plexus annotations for dependency injection as shown on the Sonotype blog.
I have a field defined in my mojo:
/**
*/
#Requirement(hint = "rhino")
private RhinoRunner rhinoRunner;
And the class defined with the #Component annotation:
/**
*/
#Component(role = RhinoRunner.class, hint = "rhino")
public class RhinoRunnerImpl implements RhinoRunner {
I then added the configuration to the components.xml. When I use the plugin the rhinoRunner field is null. If I change to use the old javadoc taglet on the dependency, like follows, it works correctly:
/**
* #component
*/
private RhinoRunner rhinoRunner;
Is it possible to make the Java5 annotations work?

The plugin annotations differ from the plexus annotations (though the plugin annotations happen to use the same mechanism to fulfil a requirement).
You should continue to use the plugin annotations in a Mojo, but feel free to use the other annotation in pure components (in the plugin or any supporting libraries).

Related

Stripping internal annotation

I have an Android library module where a public class uses some annotations from an external library. The annotations are purely used internally, so I don't want to expose it as an API Gradle dependency, leaking that dependency to clients, but keep it as an implementation one.
However, the presence of the annotation causes warnings for applications using my library, since the annotation class can not be resolved. This is actually quite understandable - a public class contains a symbol which is not on the compile path of the client - but is there a way to have annotations kept internal when packaging a library - or somehow ignored by the calling application? The annotations are RUNTIME retention ones, so they cannot be completely stripped out in a build step or similar.
Setup for illustrative purposes:
my-library:
build.gradle has implementation com.example.foobar which contains #Example annotation
Foo.java is a public class annotated with #Example:
#Example(foo = "bar")
public class Foo {
...
}
Other classes in my-library itself require the annotation to be present in runtime
some-client:
build.gradle has implementation com.example.mylibrary which contains the class Foo
This application uses Foo objects, but doesn't need to know about the annotation, however when building it will get:
classes.jar(com/example/Foo.class): warning: Cannot find annotation method 'foo()' in type 'Example': class file for com.example.Example not found
If I change implementation to API for com.example.foobar, the warning is eliminated, but the application will now get the #Example annotation on its build path, which is an internal implementation detail. Is there another way?

Access Spring beans from Alfresco integration test context

Now that Alfresco integration tests of custom modules are run using Docker, I wonder how to make additional Spring beans available in this context and how to access existing Spring beans in test classes.
Until Alfresco 5.x, I used to annotate the test class with
#ContextConfiguration("classpath:alfresco/application-context.xml")
This made the Spring context available. To make Spring beans from this context available in the test class, I annotated members like this:
#Autowired
#Qualifier("authenticationComponent")
private AuthenticationComponent authenticationComponent;
In addition I was able to define additional Spring beans in src/test/resources/alfresco/extension/test-context.xml.
Is this the approach to use when writing integration tests for 6.x and Docker?
At least the annotation org.springframework.test.context.ContextConfiguration is no longer included in a module build using the Maven 4.0.0 SDK archetype.
This blog post talks about the above mentioned annotations. But the dependencies pulled in by the pom.xml created from the SDK 4 archetype don't include these annotations.
A different approach seems to be to only use
#RunWith(value = AlfrescoTestRunner.class)
on the integration test class. But how do I get the Spring beans like nodeService injected into it? And how do I declare and make available additional Spring beans which are part of my custom module and required by the integration test to succeed?
You can get the Spring context via AlfrescoTestRunner as follows:
#Before
public void setUp() {
this.nodeService = (NodeService) super.getApplicationContext().getBean("nodeService");
}
I do the same with custom beans:
super.getApplicationContext().getBean(MyType.class);
Since the integration tests run in the repository, all of the Spring context is automatically available.
Note that your test class needs to extend AbstractAlfrescoIT for this to work.
An example class may look like this:
package nl.open.mystuff;
import org.alfresco.rad.test.AbstractAlfrescoIT;
import org.alfresco.rad.test.AlfrescoTestRunner;
import org.alfresco.service.cmr.repository.NodeService;
#RunWith(value = AlfrescoTestRunner.class)
public class MyCustomIT extends AbstractAlfrescoIT {
private NodeService nodeService;
private MyType myType;
#Before
public void setUp() {
this.nodeService = (NodeService) super.getApplicationContext().getBean("NodeService");
this.myType = super.getApplicationContext().getBean(MyType.class);
}
}
In Alfresco SDK 3, you can even add your own Spring XML files under src/test/resources/alfresco/extension/*-context.xml. I imagine this still works, but I haven't tried it with SDK 4 myself.

Processing Annotations Maven

I have a maven project and I want to create custom annotations to use in it.
I need that those annotations only be processed when some parameter is present, because I want to launch it a jenkins task.
How can I achieve it? Googling, I thought about creating a custom maven plugin for it, but I don't know how process the annotations in it.
This it is totally new for me and I would like your advice.
EDIT: I've tried creating a new maven plugin and with the reflections library find all classes with the annotation, but it isn't finding anything.
EDIT2: Following steps #Praveen Kumar, I was able to create a Custom Annotation Processor which process my method annotations. But I don't know how to execute the annotated method(I don't know either if this can be done)
#SupportedAnnotationTypes({"*"})
#SupportedSourceVersion(SourceVersion.RELEASE_8)
public class MyProcessor extends AbstractProcessor {
#Override
public boolean process(Set<? extends TypeElement annotations, RoundEnvironment roundEnv) {
for(Element el : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) {
// Execute annotated method???
}
}
}
PS. Sorry for my english.
Diego.
Solution to your question
Please use maven processor plugin for processing your custom annotations.
you can get maven processor plugin from this maven repository
Also, this example will help you a lot.
Once your maven is complete/perfect in all aspects, you can launch in Jenkins by setting your build goals.
Alternatively you can use mojo plugin to process/execute your custom annotations. please check this link if it of any help to you.

Weld on Java SE does not use alternative

I have projectA, projectB, and projectC Eclipse Maven projects.
ProjectA contains:
IMyApi interface.
"Empty" META-INF\beans.xml file.
ProjectB contains:
IMyConfig interface.
MyConfigJndi implementation of IMyConfig.
MyApiImpl implementation of IMyApi, with a property #Inject private IMyConfig config;.
"Empty" META-INF\beans.xml file.
ProjectC contains:
a MyConfigAlter implementation of IMyConfig, marked as #Alternative.
a Main class (and method) that initializes Weld SE and retrieves a IMyApi bean.
a META-INF\beans.xml where MyConfigAlter is listed in the alternatives section.
Now, I run the Main class, and the IMyApi bean is successfully retrieved (as a MyApiImpl instance). But such an instance has been, in its config property, injected with a MyConfigJndi instance, instead of the alternative version (MyConfigAlter)
I am using Eclipse Luna + M2Eclipse.
What am I doing wrong?
UPDATE: I found out that using #Specializes instead of #Alternative solves the issue, but I still think it is not the proper solution (in some situation I may not have access to the "default" implementation).
UPDATE 2:
I am using Weld-se, 2.2.10.Final:
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se</artifactId>
<version>2.2.10.Final</version>
<scope>runtime</scope>
</dependency>
And the initialization is simply
WeldContainer weld =
new Weld().
initialize();
IMyApi myApi =
weld.
instance().
select(
IMyApi.
class).
get();
Selecting an alternative using the alternatives element in the beans.xml descriptor only affects the corresponding bean archive, i.e. ProjectC in your case, as documented in Declaring selected alternatives for a bean archive. Based on that, this is logical that the ProjectB bean archive gets the MyConfigJndi implementation injected.
Since CDI 1.2, it is possible to select an alternative globally for the application using the #Priority annotation as documented in Declaring selected alternatives for an application.
So in your case, you could write:
#Priority(Interceptor.Priority.Application)
#Alternative
class MyConfigAlter {
}
Another way to solve this is to use -Dorg.jboss.weld.se.archive.isolation=false - from http://docs.jboss.org/weld/reference/2.2.11.Final/en-US/html/environments.html#_bean_archive_isolation_2
The reason that this happens is that each JAR on the classpath becomes its own bean archive. Since the CDI spec as of 1.2 does not include an SE specification there is no definition of how the classpath operates in this mode. This isn't necessarily how an SE app would be designed since you don't have unique classloaders for each JAR.

Guice Multibinding from Classpath

I'm trying to setup a plugin system for cucumber-jvm bindings with Guice as DI. The idea is to run a beforeRequest() method before each When step in Cucumber. Plugins are separate .jar found in the classpath.
Since Cucumber requires an explicit Guice module declaration in cucumber.properties, that will be used to create an Injector, I can not use standard Guice Multibindings and have a separate Module per Plugin.
An idea how it should look like:
class CucumberClazz {
Set<Plugin> plugins;
public doRequest() {
for(Plugin plugin: plugins) plugin.beforeRequest();
/* Rest of the code */
}
}
Is there a fancy option to discover all implementations of Plugin in the classpath with Guice?

Categories