jGiven Output Directory - java

Is there a way to change the output directory for the generated reports to an custom directory - in particular for the .json-Report files?
Documentation says (http://jgiven.org/userguide/ - 4.2):
[...] JGiven tries to autodetect when it is executed by the Maven surefire plugin [I'm using it] and in that case generates the reports into target/jgiven-reports/json. [...]
I'm using jGiven with Maven (for Appium Tests).
Configuration (pom.xml - dependencies):
<dependency>
<groupId>com.tngtech.jgiven</groupId>
<artifactId>jgiven-testng</artifactId>
<version>0.15.1</version>
<scope>test</scope>
</dependency>
Configuration (pom.xml - build/plugins):
<plugin>
<groupId>com.tngtech.jgiven</groupId>
<artifactId>jgiven-maven-plugin</artifactId>
<version>0.15.1</version>
<executions>
<execution>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
Since the directory is defined by jGiven it does not help to change the build-directory. It would still use the target/jgiven-reports/json directory.
Thanks in advance!

If somebody else is curious:
I found: String reportDirName = System.getProperty( JGIVEN_REPORT_DIR ); in https://github.com/TNG/JGiven/blob/fae0f3c8db0b00e7fa233cbd8f86306379def4b2/jgiven-core/src/main/java/com/tngtech/jgiven/impl/Config.java#L31 (current master).
Important part of it:
private static final String TRUE = "true";
private static final String FALSE = "false";
private static final String AUTO = "auto";
private static final String JGIVEN_REPORT_ENABLED = "jgiven.report.enabled";
public static final String JGIVEN_REPORT_DIR = "jgiven.report.dir";
private static final String JGIVEN_REPORT_TEXT = "jgiven.report.text";
private static final String JGIVEN_REPORT_TEXT_COLOR = "jgiven.report.text.color";
private static final String JGIVEN_FILTER_STACK_TRACE = "jgiven.report.filterStackTrace";
So you can either set your system properties via the maven-surefire-plugin in the pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.5</version>
<configuration>
<systemPropertyVariables>
<jgiven.report.dir>/my/custom/dir</jgiven.report.dir>
</systemPropertyVariables>
</configuration>
</plugin>
or just use Java's System.setProperty("jgiven.report.dir", "/my/custom/dir")

Related

AspectJ plugin builds fine but at runtime annotations don't work

I am using the AspectJ Maven plugin to build my project and use an AspectLibrary, which is a jar in which I have my aspects defined.
Here is the Aspect that I am trying to use
#Around("execution(* *(..))&&#annotation(com.cisco.commerce.pricing.lp.commons.util.annotations.TimeMe)")
public Object timeMeAroundAspect(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {// NOSONAR
Timer timer = Timer.instance().start();
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
Method method = signature.getMethod();
TimeMe timeMeAnnotation = method.getAnnotation(TimeMe.class);
String name = timeMeAnnotation.name();
boolean log = timeMeAnnotation.log();
boolean addToMetrics = timeMeAnnotation.addToMetrics();
Object response = null;
try {
response = proceedingJoinPoint.proceed();
} finally {
try {
Long timeTaken = timer.timeTaken();
if (log) {
LOGGER.info("MethodName: {} Time taken: {}", name, timeTaken);
}
if (addToMetrics) {
ExecutionDetailsUtil.addMethodExecutionTime(name, timeTaken);
}
} catch (Exception e) {
LOGGER.warn("Exception while trying to log time", e);
}
}
return response;
}
This code is in a jar file, which I am using as the aspectLibrary in my pom
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<encoding>UTF-8</encoding>
<source>${java.source-target.version}</source>
<target>${java.source-target.version}</target>
<Xlint>ignore</Xlint>
<aspectLibraries>
<aspectLibrary>
<groupId>it.cvc.ciscocommerce.lps.lp-commons</groupId>
<artifactId>lp-commons</artifactId>
</aspectLibrary>
</aspectLibraries>
<complianceLevel>${java.source-target.version}</complianceLevel>
</configuration>
<executions>
<execution>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
Below is my annotation defintion
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface TimeMe {
public String name();
public boolean log() default true;
public boolean addToMetrics() default true;
}
Here is the snippet where I am trying to use this annotation (in a different code base which uses the above jar as a dependency)
#TimeMe(name = "classifyLine")
private void classifyLine(PricingObject pricingObject,
PricingLineObject pricingLineObject, LineTypes lineTypes) {
//logic
}
My build runs fine and prints the following in the MAVEN Console
[INFO] Join point 'method-execution(void com.cisco.pricing.lps.main.ListPriceService.classifyLine(com.cisco.pricing.lps.bean.PricingObject, com.cisco.pricing.lps.bean.PricingLineObject, com.cisco.pricing.lps.dto.LineTypes))' in Type 'com.cisco.pricing.lps.main.ListPriceService' (ListPriceService.java:235) advised by around advice from 'com.cisco.commerce.pricing.lp.commons.util.logging.LoggingAspectDefiner' (lp-commons-2019.03.01-SNAPSHOT.jar!LoggingAspectDefiner.class(from LoggingAspectDefiner.java))
I exploded the war file and looked at the class files generated. I have the following AjcClosure1 class generated for the java file where I used the annotation.
public class ListPriceService$AjcClosure1 extends AroundClosure {
public Object run(Object[] paramArrayOfObject) {
Object[] arrayOfObject = this.state;
ListPriceService.classifyLine_aroundBody0((ListPriceService)
arrayOfObject[0],
(PricingObject)arrayOfObject[1],
(PricingLineObject)arrayOfObject[2], (LineTypes)arrayOfObject[3],
(JoinPoint)arrayOfObject[4]);return null;
}
public ListPriceService$AjcClosure1(Object[] paramArrayOfObject)
{
super(paramArrayOfObject);
}
}
And in the java class file, where I use the annotation, I see no changes to the classifyLine method.
However, when I run my application, the annotation is not working. It doesn't execute the Aspect I have defined in the jar.
I have no clue why. Is my pattern not matching? It matches and works fine in a Spring application but not in this non Spring application.

Get annotations when exec-maven-plugin runs Main does not work

I would like to run a Main class with exec-maven-plugin and from my dependencies generate documentation like a swagger file.
The annotation that I care is javax.ws.rs.Path which has #Retention(RetentionPolicy.RUNTIME)
My Java code
public class ContextClassReader extends ClassReader {
private static final ExtensibleClassLoader CLASS_LOADER = new ExtensibleClassLoader();
public ContextClassReader(final String className) throws IOException {
super(CLASS_LOADER.getResourceAsStream(className.replace('.', '/') + ".class"));
final URL resource = CLASS_LOADER.getResource(className.replace('.', '/') + ".class");
}
public static ClassLoader getClassLoader() {
return CLASS_LOADER;
}
public static void addClassPath(final URL url) {
CLASS_LOADER.addURL(url);
}
private static class ExtensibleClassLoader extends URLClassLoader {
ExtensibleClassLoader() {
super(new URL[]{});
}
#Override
public void addURL(final URL url) {
super.addURL(url);
}
}
Here is the loading of class and testing it for annotations.
final Class<?> clazz = ContextClassReader.getClassLoader().loadClass(className);
isAnnotationPresent(clazz);
public static boolean isAnnotationPresent(final AnnotatedElement annotatedElement) {
... annotatedElement.getAnnotations().length --> 0
... clazz.getMethods().length() ---> works !
}
My pom.xml
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>java</executable>
<workingDirectory>XXXXXXXXXXXXXXXXXXX</workingDirectory>
<addResourcesToClasspath>true</addResourcesToClasspath>
<additionalClasspathElements>true</additionalClasspathElements>
<includeProjectDependencies>true</includeProjectDependencies>
<includePluginDependencies>true</includePluginDependencies>
<includeProjectDependencies>true</includeProjectDependencies>
<mainClass>XXX.Main</mainClass>
</configuration>
</plugin>

Exception Handling/Mapping for a particular class

I have resource class which itself's talks with a internal service. This resource acts a rest API for the service. The service layer can throw unexpected exceptions, thus the resource should handle those handled unexpected exceptions and log it. I am using dropwizard framework which in turns use jersey. It goes like this.
#PATH(/user)
#GET
public Response getUser(#QueryParam("id") String userId) {
assertNotNull(userId);
try {
User user = service.getUser(userId);
return Response.ok(user).build();
}
catch (MyOwnException moe) { //basically 400's
return Response.status(400).entity(moe.getMsg()).build();
}
catch (Exception e) { //unexpected exceptions
logger.debug(e.getMessage);
return Response.status(500).entity(moe.getMsg()).build();
}
}
The problem here is that i have to do this exact same exception handling for each REST api endpoint. Can i do some kind of exception mapping for this particular resource so that i can put all the handling logic and logging there?
I know i can build a mapper for an particular exception in jersey, but that is for the whole module not a single class.
Afaig you can't register an ExceptionMapper to a resource method. I've tried this by implementing a DynamicFeature which was looking for a custom Annotation and then tried to register a custom ExceptionMapper with the FeatureContext.
The result was disillusioning:
WARNING: The given contract (interface javax.ws.rs.ext.ExceptionMapper) of class path.to.CustomExceptionMapper provider cannot be bound to a resource method.
Might not work:
But...
For a resource class this is in fact easy. Just register your ExceptionMapper for your resource class within your ResourceConfig. For me it looks like:
#ApplicationPath("/")
public class ApplicationResourceConfig extends ResourceConfig {
public ApplicationResourceConfig() {
// [...]
register(YourExceptionMapper.class, YourResource.class);
// [...]
}
}
So if you are okay with having this on resource class level, do it like this.
Otherwise you might need to use Aspects (but I don't see any reasons to do so). Example:
Aspect
#Aspect
public class ResourceAspect {
Logger logger = [...]
private static final String RESOURCE = "execution(public !static javax.ws.rs.core.Response path.to.resources..*(..)) && #annotation(path.to.HandleMyOwnException)";
#Around(RESOURCE)
public Object translateRuntimeException(ProceedingJoinPoint p) throws Throwable {
try {
return p.proceed();
} catch (MyOwnException moe) {
return Response.status(400).entity(moe.getMsg()).build();
} catch (Exception e) { //unexpected exceptions
logger.debug(e.getMessage);
return Response.status(500).entity(e.getMessage()).build();
}
}
}
Please notice, the RESOURCE config. Here it works for none static methods under path.to.resources which returning Response and are anntotated with the HandleMyOwnException annotation.
HandleMyOwnException
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface HandleMyOwnException {}
ResourceMethod
#GET
#PATH("/user")
#HandleMyOwnException
public Response getUser(#QueryParam("id") String userId) {
assertNotNull(userId);
return Response.ok(service.getUser(userId)).build();
}
pom.xml
<!-- deps -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.2</version> <!-- or newer version -->
</dependency>
<!-- build plugins -->
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<showWeaveInfo>true</showWeaveInfo>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<versionRange>[1.7,)</versionRange>
<goals>
<goal>compile</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
<plugins>
<pluginManagement>
Have a nice day!
EDITED
~ Added more complete pom.xml config
~ Corrected missing path for Annotation in ResourceAspect
Why not just factor out the exception handling into a private method?
#PATH(/user)
#GET
public Response getUser(#QueryParam("id") String userId) {
assertNotNull(userId);
return handleExceptions(() -> {
User user = service.getUser(userId);
return Response.ok(user).build();
});
}
private Response handleExceptions(Callable<Response> callable) {
try {
return callable.call();
}
catch (MyOwnException moe) { //basically 400's
return Response.status(400).entity(moe.getMsg()).build();
}
catch (Exception e) { //unexpected exceptions
logger.debug(e.getMessage);
return Response.status(500).entity(e.getMessage()).build();
}
}

Where to generate ressources into during Annotation processing in a maven workflow?

I have a maven project with several modules, i.e.
<module>backend</module> <!-- provides annotations -->
<module>annotationProcessor</module> <!-- processes ann., generates files -->
<module>mainprog</module> <!-- uses annotations/files -->
backend provides an annotation class MyAnnotation for annotating classes.
mainprog contains Mainprog.java which defines a class with a #MyAnnotation annotation. At runtime this class tries to load a file via getResourceAsStream("Mainprog.properties") (which does not exist yet).
The annotationProcessor has a class MyAnnotationProcessor which maven executes and finds my annotations.
The processor should create the file Mainprog.properties from information gathered by the annotation processor.
I can not manage to put the properties file in a place where it is found when executing/testing Mainprog.
Where should I generate the file to into, being in a maven workflow?
How do I tell maven this file is used in tests or at runtime? Eventually
is has to be packaged in the jar.
Mainprog
package demo;
#MyAnnotation
public class Mainprog {
}
Use the properties file
Currently I do it in the testing class, but later this will be in the class itself.
package demo;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.junit.Test;
public class MainprogTest {
Class testclass = Mainprog.class;
#Test
public void testPropertiesFile() throws IOException {
String fn = testclass.getCanonicalName().replace('.', '/') + ".properties";
System.err.println("loading: '"+fn+"'");
InputStream in = getClass().getResourceAsStream(fn);
Properties prop = new Properties();
prop.load(in);
in.close();
}
}
This currently runs as such:
loading: 'demo/Mainprog.properties'
Tests in error:
testPropertiesFile(demo.MainprogTest)
with a NullPointerException, because the stream returns null, i.e. does not exist.
Despite the file is there (but is it in the right place?):
towi#havaloc:~/git/project/mainprog$ find . -name Mainprog.properties
./src/java/demo/Mainprog.properties
./target/classes/demo/Mainprog.properties
Processor
package demo;
import com.github.javaparser.*;
import com.github.javaparser.ast.*;
import javax.annotation.processing.*;
import javax.lang.model.element.*;
#SupportedAnnotationTypes({"demo.MyAnnotation"})
public class MyAnnotationProcessor extends AbstractProcessor {
#Override
public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env) {
for (TypeElement te : elements) {
for (Element e : env.getElementsAnnotatedWith(te))
{
processAnnotation(e);
}
}
return true;
}
private void processAnnotation(Element elem) {
final TypeElement classElem = (TypeElement) elem;
...
final String prefix = System.getProperty("user.dir").endsWith("/"+"mainprog") ? "." : "mainprog";
final String className = classElem.getQualifiedName().toString();
String fileName = prefix + "/src/java/" + className.replace('.', '/') + ".java";
FileInputStream in = new FileInputStream(fileName);
final CompilationUnit cu = JavaParser.parse(in);
final CallGraph graph = ...
generateInfoProperties(classElem, fileName, graph);
}
private void generateInfoProperties(TypeElement classElem, String inFilename, CallGraph graph) throws IOException {
final File outFile = new File(inFilename
.replace("/src/java/", "/src/java/") // <<< WHERE TO ???
.replace(".java", ".properties"));
outFile.getParentFile().mkdirs();
try (PrintWriter writer = new PrintWriter(outFile, "UTF-8")) {
final Properties ps = new Properties();
graph.storeAsProperties(ps);
ps.store(writer, inFilename);
writer.close();
}
}
}
As you can see, there is a lot of guesswork and "heuristics" going on when handling directory names. All that System.getProperty("user.dir") and replace("/src/java/", "/src/java/") is probably wrong, but what is better?
maven
In Maven I have 4 poms, of course
pom.xml
backend/pom.xml
annotationProcessor/pom.xml
mainprog/pom.xml
Only one of seems to me contains anything of note, i.e., the execution of the annotation processor in mainprog/pom.xml:
<project>
....
<dependencies>
<dependency>
<groupId>project</groupId>
<artifactId>backend</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>project</groupId>
<artifactId>annotationProcessor</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>mainprog</finalName>
<sourceDirectory>src/java</sourceDirectory>
<resources>
<resource>
<directory>${basedir}/src/conf</directory>
<targetPath>META-INF</targetPath>
</resource>
<resource>
<directory>${basedir}/web</directory>
</resource>
<resource>
<directory>${basedir}/src/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
<include>**/*.wsdl</include>
<include>**/*.xsd</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessors>
<annotationProcessor>demo.MyAnnotationProcessor
</annotationProcessor>
</annotationProcessors>
</configuration>
</plugin>
...
</plugins>
</build>
</project>
I thought by generating the file into /src/java/ and then having <resource><directory>${basedir}/src/java and <include>**/*.properties is enough, but it does not seem so. Why is that?
Use the provided Filer, which can be obtained using processingEnv.getFiler(). If you create a source file using it, the compiler will compile it on the next round and you won't need to worry about configuring Maven to compile generated source files.

Debugging a ClassNotFoundException throw my a Maven Mojo when using #requiresDependencyResolution in a Mojo

A ClassNotFoundException is being thrown in a plugin I've developed. The class which can't be founf definitely exists and its associated project is included as a dependency in the executing project's pom.xml file as follows:
<dependency>
<groupId>com.example</groupId>
<artifactId>project-one</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
My plugin is included the executing pom.xml as follows:
<build>
<plugins>
<plugin>
<groupId>com.example</groupId>
<artifactId>project-two-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<configuration>
<customSettingOne>
setting
</customSettingOne>
</configuration>
<phase>prepare-package</phase>
<goals>
<goal>some-task</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
My plugin class is as follows:
/**
* #goal some-task
*
* #requiresDependencyResolution compile
*/
public class MyPluginMojo extends AbstractMojo {
/**
* Directory to save the CSV files to.
*
* #parameter alias="customSettingOne"
* #required
*/
private File customSettingOne;
}
I have tried this code using:
Apache Maven 2.2.1 (r801777; 2009-08-06 20:16:01+0100)
and the embedded version used by Eclipse m2e
Embedded (3.0.2/1.0.200.20111228-1245
I get a ClassNotFoundException when my plugin code tried to load the class from ProjectOne.
Anyone have any ideas how I can get to the bottom of this? Is it possible to inspect or dump out the classpath being used in the plugin?
I would check here first:
Guide to Maven Classloading
and if that doesn't help, maybe a bit of diagnostic code like the following:
package stackoverflow;
import java.net.URL;
import java.net.URLClassLoader;
public class PrintClassLoader {
public static void main(String[] args) {
PrintClassLoader pcl = new PrintClassLoader();
pcl.printClassLoader(pcl.getClass().getClassLoader());
}
public void printClassLoader(ClassLoader classLoader) {
if (null == classLoader) {
return;
}
System.out.println("--------------------");
System.out.println(classLoader);
if (classLoader instanceof URLClassLoader) {
URLClassLoader ucl = (URLClassLoader) classLoader;
int i = 0;
for (URL url : ucl.getURLs()) {
System.out.println("url[" + (i++) + "]=" + url);
}
}
printClassLoader(classLoader.getParent());
}
}
For example will print something like:
--------------------
sun.misc.Launcher$AppClassLoader#35ce36
url[0]=file:/D:/dev/workspaces/3.6/all/Z_temp/target/classes/
url[1]=file:/D:/dev/.m2/repository/javax/mail/mail/1.4/mail-1.4.jar
url[2]=file:/D:/dev/.m2/repository/javax/activation/activation/1.1/activation-1.1.jar
url[3]=file:/D:/dev/.m2/repository/commons-io/commons-io/2.1/commons-io-2.1.jar
--------------------
sun.misc.Launcher$ExtClassLoader#757aef
url[0]=file:/C:/java/jdk/jdk1.6.0_31/jre/lib/ext/dnsns.jar
url[1]=file:/C:/java/jdk/jdk1.6.0_31/jre/lib/ext/localedata.jar
url[2]=file:/C:/java/jdk/jdk1.6.0_31/jre/lib/ext/sunjce_provider.jar
url[3]=file:/C:/java/jdk/jdk1.6.0_31/jre/lib/ext/sunmscapi.jar
url[4]=file:/C:/java/jdk/jdk1.6.0_31/jre/lib/ext/sunpkcs11.jar

Categories

Resources