I've got a multi-module Selenium project that's using the Page Factory and running tests through Suites by calling mvn clean verify...
I've created a JavaFX app that loads all the Suites and lets the user select a test, which is then run by the above-mentioned command.
The problem I'm facing now is that, in order to load all the test classes (I'm using test-jar in module dependencies so that my test class in the app module can see the tests in the other modules), I need to have the main method in a test class, and not in a main class.
Obviously, that doesn't work since the test classes are not included in the jar.
I'm looking for a solution, either on having that main method in a test class, or for src/main to see into src/test.
One of the recommendations people have been giving is to have a separate module for the tests. This is not an option for me though as I don't have the rights to move the tests classes around or change the project structure that much.
Here's the plugin I'm using:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.package.myapp.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
For loading the suites, I use ClassLoader loader = Thread.currentThread().getContextClassLoader() which gets an ImmutableSet<ClassPath.ClassInfo> from ClassPath.from(loader).getTopLevelClasses()
This is a standard problem about decoupling modules: You have two modules: Dependent Module and Independent Module. You need the Independent to be invoked from the Dependent one, but without including the Independent in the Dependent's compilation.
So, you have several options to chose:
When the API and protocol of Independent modules is known at compile-time.
In this case, you should design an interface to model each Independent API. Publish these interfaces into a separated library, and retro-extend the Independent library to these interfaces. Provide also a factory which returns objects of these interfaces, by dynamic instantiation of a set of classes names (received at run time).
In the Dependent module, you just have to invoke the factory to obtain each interface implementation and use it.
When the API and protocol of independent modules is not known at compile-time.
Uh, uh...! I hope sincerely this is not your case, because it does not fit in the good practices of standard design.
Anyway, in Java you can always invoke any method in any object through the use of reflection. Though I won't advise it.
Related
import software.amazon.awscdk.services.lambda.Function;
Function helloLambda = new Function(helloStack, "hellocdkworld123", FunctionProps.builder()
.functionName("HelloLambda")
.code(Code.fromAsset("target/cdkhello-0.1.jar")) // <- x ?
.runtime(Runtime.JAVA_8)
.handler("com.myorg.functions.HelloLambda::sayHello") <- y?
.build());
There is also a possibility to reference it by S3 bucket. But when I run cdk bootstrap I get a generated bucket with generated name of the jar file. How should I be able to reference that before hand from code? Of course now I could write the exact bucket + file but then purpose of defining it from code is lost right?
First of all, assuming that the method that you want to execute when the Lambda is invoked is sayHello, from the com.myorg.functions.HelloLambda class, then that part of your solution is correct. The more difficult part is actually accessing the JAR with your Lambda code in it.
NOTE: I've updated my original answer with what I think is a better way to accomplish this. In order to avoid confusion and making this answer too wordy, I've removed the original answer, though much of it is common with this one. I credit this answer for helping to improve this answer.
Pass the path to the dependent resource's JAR to CDK
TL;DR
Create a new property for the full path to your Lambda JAR.
Associate dependency and execution related goals into the package phase of the build.
Update cdk.json to point to the the package phase.
Pass the full path via a system property to your CDK code.
Use the System property to pass to Code.asset(...).
Preparation
I've separated out the Lambda and the CDK infrastructure code into separate Maven modules. The intention being that once the Lambda code is compiled, packaged up into an uber JAR (its code plus all of its dependencies' code), the infrastructure module can refer to it as a dependency, passing the full path to the Lambda JAR to the App/Stack class to that it can use it as an asset.
Create a new property for the full path to your Lambda JAR.
In the properties section of your pom.xml, create a new property to refer to your Lambda JAR. Something like this:
<properties>
...
<lambda.jar>${GROUP_ID:ARTIFACT_ID:jar}</lambda.jar>
...
</properties>
Populate a property with the full path to your Lambda dependency's JAR, using the dependency plugin.
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<goals>
<goal>properties</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
</plugin>
...
<plugins>
</build>
This associates the properties goal with the process-resources phase. Whenever that phase of the build occurs, the property you've created previously will be populated with the full path to the JAR in your local repository.
Associate dependency and execution related goals into a single phase of the build.
When you create a new CDK Java project, it outputs a file called cdk.json, which points by default to the Maven exec:java goal. In order for your new lambda.jar property to be populated correctly, you need to associate the exec:java goal with the same phase as above.
<build>
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<mainClass>com.myorg.TestingApp</mainClass>
</configuration>
</plugin>
...
</plugins>
</build>
In order for your code to get access to the JAR file that you've generated, you need to create a System property (I couldn't get environment variables to work) to your App class. Your pom.xml started with something like this:
Pass the full path via a system property to your CDK code.
In the configuration section (after mainClass), add a system property for your assets directory, something like this:
<systemProperties>
<systemProperty>
<key>lambda.jar</key>
<value>${lambda.jar}</value>
</systemProperty>
</systemProperties>
Update cdk.json to point to the the common phase you've used.
Your cdk.json of your CDK project should be changed to point to the process-resources phase. Once done it will look like this:
{
"app": "mvn package"
}
It will cause both the goals to be run in succession, and upon execution the path to your Lambda's JAR will be passed as a system property.
Access the property from your App/Stack code.
Finally, now that the system property is created, you can access it from your code by calling System.getProperty("lambda.jar"). Something like this:
final Code code = Code.fromAsset(System.getProperty("lambda.jar"));
You can then use the code reference wherever needed when defining your Lambda functions.
I have a largish multimodule Maven build. I need to generate the javadoc for all of the modules and produce an "aggregated" javadoc result that I can deploy to a box for consumption by users.
I did have this working perfectly fine for quite a while, until I tried implementing a custom taglet with specific features and requirements, which makes this more complicated to produce.
All of the submodules inherit a parent pom that is not the aggregator pom. In that parent pom I define the maven-javadoc-plugin. This is what it looked like before I added the custom taglet:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
<configuration>
<additionalparam>-Xdoclint:none</additionalparam>
<bottom>Unified Service Layer - bottom</bottom>
<doctitle>Unified Service Layer - title</doctitle>
<footer>Unified Service Layer - footer</footer>
<groups></groups>
<header>Unified Service Layer - header</header>
<level>public</level>
<packagesheader>Unified Service Layer - packagesheader</packagesheader>
<top>Unified Server Layer - top</top>
<windowtitle>Unified Service Layer - windowtitle</windowtitle>
</configuration>
<executions>
<execution>
<id>module-javadoc-jar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<show>protected</show>
<detectLinks>false</detectLinks>
</configuration>
</execution>
<execution>
<id>aggregated-documentation</id>
<phase>package</phase>
<inherited>false</inherited>
<goals>
<goal>aggregate-jar</goal>
</goals>
<configuration>
<show>protected</show>
<detectLinks>false</detectLinks>
</configuration>
</execution>
</executions>
</plugin>
With this, I could build all all of the modules, which will generate their own javadoc (which I now know is just a validation step, as aggregate-jar doesn't use this output). I have a separate step I call from jenkins that runs "javadoc:aggregate-jar" in the root project, which produces the aggregated javadoc jar that I deploy.
Again, this has been working fine until now.
I implemented a custom javadoc taglet which requires getting access to the Class object associated with the source file it is contained within. I got this to work, at least in the individual module builds by adding the following to the configuration above:
<taglets>
<taglet>
<tagletClass>com.att.det.taglet.ValidationConstraintsTaglet</tagletClass>
</taglet>
<taglet>
<tagletClass>com.att.det.taglet.ValidationConstraintsCombinedTaglet</tagletClass>
</taglet>
</taglets>
<tagletArtifacts>
<tagletArtifact>
<groupId>com.att.detsusl.taglets</groupId>
<artifactId>validationJavadocTaglet</artifactId>
<version>0.0.1-SNAPSHOT</version>
</tagletArtifact>
</tagletArtifacts>
In order to have the taglet get access to the class file, I had to add a minimal plugin configuration to each subproject pom.xml, which looks like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<tagletArtifacts combine.children="append">
<tagletArtifact>
<groupId>com.att.detsusl</groupId>
<artifactId>artifact-name</artifactId>
<version>${current.pom.version}</version>
</tagletArtifact>
</tagletArtifacts>
</configuration>
</plugin>
With these minimal changes, I could run the build in each module, generating the javadoc, and examining the generated javadoc output in each module, verifying that it all worked.
However, the problem is, when I run "javadoc:aggregate-jar" in the root project, all of that already built output is ignored. It reruns the javadoc generation for all of the subprojects, also ignoring the appended tagletArtifacts list in each subproject pom.xml file. As a result, I get ClassNotFound errors when it tries to get the class file.
I could "fix" this by putting all of the subproject GAVs into the top-level "tagletArtifacts" list, but I definitely do not want to do that. I liked the ability to specify this in the subproject pom.xml (with combine.children="append") to make it work.
What I need is an overall javadoc package for all of the subprojects, with the taglet able to get access to the class file, without forcing the parent pom to know about all of its subprojects. How can I do this?
I'm facing the same problem with all aggregate goals. I checked the source code to maven-javadoc-plugin and it turns out that aggregate work by traversing submodules and collecting source files and nothing more, thus completely ignoring any form configurations specified in the submodules.
During execution every submodule is completely ignored:
source
if ( isAggregator() && !project.isExecutionRoot() ) {
return;
}
And during collection of source files submodules are traversed: source
if ( isAggregator() && project.isExecutionRoot() ) {
for ( MavenProject subProject : reactorProjects ) {
if ( subProject != project ) {
List<String> sourceRoots = getProjectSourceRoots( subProject );
So at the moment, there is no way to do this.
This is not easy to fix either since the whole plugin works by composing a single call to the actual javadoc tool. If you would like to respect settings in the submodules as well, you'll have to merge the configuration blocks of them. While this would work in your case with tagletArtifacts, it does not work for all the settings you can specify, e.g. any form of filter, and can therefore not be done in a generic way.
I have a somewhat large multi-module Maven project. I have the unit tests in each module being processed by Jacoco. I have a separate child module doing "merge" and "report-aggregate", and this appears to be generating data. I'm even using the generated data in SonarQube. Most of my tests are using PowerMock, and I'm using offline instrumentation.
However, after looking closer at the coverage data, I see that it is leaving out coverage data for classes and methods that I know are being executed during tests. The pattern I see in every module is that it only reports coverage for a single class in each module, which is a class actually in the current module. Almost all of the tests also call out to other classes in other modules in the build, and coverage for those classes are never reported.
The following plugin configurations are in the parent pom used by each child module:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.8</version>
<executions>
<execution>
<id>default-instrument</id>
<goals>
<goal>instrument</goal>
</goals>
</execution>
<execution>
<id>default-restore-instrumented-classes</id>
<goals>
<goal>restore-instrumented-classes</goal>
</goals>
</execution>
<execution>
<id>default-report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<argLine>-Xmx1024m</argLine>
<includes>
<include>**/*Test.java</include>
</includes>
<systemPropertyVariables>
<jacoco-agent.destfile>${project.build.directory}/jacoco.exec</jacoco-agent.destfile>
<running-unit-test>true</running-unit-test>
</systemPropertyVariables>
</configuration>
</plugin>
When I inspect the generated HTML results for each module, I find that it only reports results for the single class in the current module, and not the data for classes in other modules. From this, I would assume that how I do "merge" and "report-aggregate" in the separate child module is probably irrelevant to this problem.
The generated "jacoco.exec" file is binary, but I tried "catting" out one from one module just to see what ascii text was visible, and it showed only one occurrence of anything that looked like a file name, and it was the only file name reported in the HTML coverage report for that module.
I'm not sure what other information I can report.
Update:
I guess I can see pretty clearly now that when surefire runs unit tests, it uses the instrumented classes from the current module, but the uninstrumented classes from the maven artifacts. This is why I only see coverage for classes in the current module.
So it seems like I need a way to specify that the "target/generated-classes/jacoco" folder for each module the current module depends on, is prepended to the classpath that surefire uses. I don't see a way to do that.
Alternatively, I see that the "instrument" goal has an "includes" configuration element. Should I be specifying paths to all of the "target/classes" directories for each of the modules that the current module depends on?
Recording of code coverage for some class requires its instrumentation. Goal instrument performs instrumentation of classes of current module.
all of the tests also call out to other classes in other modules
so the ones that are not instrumented. And if I correctly understood, then exactly those for which you are missing coverage.
If you don't use PowerMock for classes that come from other modules, but only for classes in current module, then you can combine offline instrumentation with on-the-fly using agent. But in this case make sure that classes instrumented offline are explicitly excluded from instrumentation by agent, otherwise agent will be throwing IllegalStateException: Class ... is already instrumented.
If you use PowerMock for classes that come from other modules, then this becomes more complex due to strictness of Maven in regards of manipulations with classpaths and dependencies. And I doubt that this can be easily achieved using one mvn comand, however seems possible using more:
instrument and run tests, but don't use restore-instrumented-classes
restore classes and generate report(s)
Unfortunately you haven't provided complete example (https://stackoverflow.com/help/mcve) and I don't have time to prepare full example to test this approach right now.
As a side note: inability to simply use agent comes from the fact that PowerMock bypasses any agent and reads class files from disk.
can there be a maven plugin instead of javaagent to reduce startup time of an application? Many ORM tools have both javaagent and maven plugin, so it should be possible - is it? Or at least something like "CompiledClassFilesBuilder" similar in functionality to AgentBuilder :-)
Regards,
Pavel
It is perfectly possible to use Byte Buddy from within a Maven plugin. You can implement a ClassFileLocator for the Maven target after the compile phase and redefine the classes within this folder using a ByteBuddy instance. The API is identical to that of the AgentBuilder inside a transformer.
You would need to implement such a plugin, though. There is none currently existing.
Do however note that this static transformation has its limitations. Using a plugin, it is not possible to redefine bootstrap classes of the VM. It would also be difficult to change library classes as they are external artifacts. Finally, Byte Buddy can register live callbacks that need to be set wt runtime.
UPDATE: I just added the plugin in question and will release a Maven Byte Buddy plugin in version 1.4.21. A transformation can be added as follows:
<plugin>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>transform</goal>
</goals>
</execution>
</executions>
<configuration>
<transformations>
<transformation>
<plugin>net.bytebuddy.test.SimplePlugin</plugin>
<!-- Optionally, specify groupId, artifactId, version of the class -->
</transformation>
</transformations>
<!-- Optionally, add 'initialization' block with EntryPoint class -->
</configuration>
</plugin>
The two relevant interfaces Plugin and EntryPoint are added to the library directly and are straight-forward to implement.
I have a library created by myself with simple logging annotations and logger aspect.
I have several AspectJ projects where I want to reuse this library compiled into the jar.
Library is very similar to http://www.jcabi.com/ library with it's #Loggable annotation, but has some differences, main difference is that my library aspect tries to retrieve a Username if class of method marked as #Loggable implements HasUser interface (my own interface). Other differences are not so important.
I want an example of Ant script to compile both from library and project aspects.
AspectJ Ant Documentation is too complex for me because I have little experience with Ant.
Partially similar questions are hear:
aspectj: How to weave aspects from a library into user code?
iajc fails to weave aspects from a jar but succeedes from class files
I would recommend to use jcabi-maven-plugin, which weaves your .class files using AspectJ aspects from your current Maven module (in src/main/aspect) and from all its dependencies:
<plugin>
<groupId>com.jcabi</groupId>
<artifactId>jcabi-maven-plugin</artifactId>
<version>0.7.19</version>
<executions>
<execution>
<goals>
<goal>ajc</goal>
</goals>
</execution>
</executions>
</plugin>