Scan custom annotated classes from maven plugin - java

I have a "simple maven project" that contains a package with some custom annotated classes.
I'm currently developing a maven plugin that can scan my "simple project" for those annotated classes and then return their name and the associated package.
For exemple :
simple-project/src/main/java/myApp/domain/Entity.java with Entity annotated with #MyCustomAnnotation
and the "my-maven-plugin" project is declared in the "simple-project" pom.xml
So, if I run "mvn generator:myGoal" it should generate a file with this content : myApp.domain.Entity
I tried almost everything I found on the internet but nothing really worked.
Everytime I run my goal, my plugin scans for its own classes but not my simple-project classes.
Any help would be appreciated.
Thanks.

I found a solution.
I loop on the sourceDirectory with a recursive function to find all files.
Here is how I get the sourceDirectory from my mojo :
/**
* Project's source directory as specified in the POM.
*
* #parameter expression="${project.build.sourceDirectory}"
* #readonly
* #required
*/
private final File sourceDirectory = new File("");
fillListWithAllFilesRecursiveTask(sourceDirectory);
I get the path of those files and then I use com.google.code.javaparser to parse the associated FileInputStream.
public void fillListWithAllFilesRecursiveTask(final File root) {
CompilationUnit cu;
FileInputStream in;
try {
// we looped through root and we found a file (not a directory)
in = new FileInputStream(file);
cu = JavaParser.parse(in);
new MethodVisitor().visit(cu, file);
Finally, I extend the VoidVisitorAdapter to get Annotations and members...etc
private static class MethodVisitor extends VoidVisitorAdapter<File> {
#Override
public void visit(ClassOrInterfaceDeclaration n, File file) {
if (n.getAnnotations() != null) {
// store classes that are annotated
for (AnnotationExpr annotation : n.getAnnotations()) {
//here some logic
}
} ...

Related

junit5 create temp file

I wrote a unit test with junit 5 that tests some file system logic for which I need a folder and some files. I found the TempDir annotation in the documentation and used that to create a folder, into which I saved some files. Something like:
#TempDir
static Path tempDir;
static Path tempFile;
// ...
#BeforeAll
public static void init() throws IOException {
tempFile = Path.of(tempDir.toFile().getAbsolutePath(), "test.txt");
if (!tempFile.toFile().createNewFile()) {
throw new IllegalStateException("Could not create file " + tempFile.toFile().getAbsolutePath());
}
// ...
}
In junit4 it was possible to use TemporaryFolder#newFile(String). This doesn't seem to be around in junit5.
Am I missing something? It works so I suppose that's fine but I was wondering if there is a cleaner way to create a new file directly with the junit 5 api.
You can simplify the amount of typing for getting temp files if you make use of the built in methods of Files. This is a more concise definition to provide tempFile which should give similar error handling:
#TempDir
static Path tempDir;
static Path tempFile;
#BeforeAll
public static void init() throws IOException {
tempFile = Files.createFile(tempDir.resolve("test.txt"));
}
Ensure that you have a recent version of JUNIT5. The test below should pass, but fails in some older versions of JUNIT which do not generate unique values of #TempDir for fields tempDir and mydir:
#Test void helloworld(#TempDir Path mydir) {
System.out.println("helloworld() tempDir="+tempDir+" mydir="+mydir);
assertFalse(Objects.equals(tempDir, mydir));
}
As shown here (https://www.baeldung.com/junit-5-temporary-directory) you can either annotate a File or a Path with #TempDir, and write to the designated File using java.nio.Files#write with a Path for its target argument.

Failed to load the sqljdbc_auth.dll when running multiple JBehave Stories via Maven

I'm working with a Maven project that has three modules:
Database
Module that contains a JBehave Story (Story .java, .story, and steps .java file)
Another module that contains a JBehave Story (Story .java, .story, and steps .java file)
Both of the modules that contain a JBehave Story have the same type of .java file that runs the .story file and steps. Below is the .java file both modules have (but have different names for test purposes):
public class FirstStories extends ConfigurableEmbedder {
private SqlDataSourceProvider dataSourceProvider = new SqlDataSourceProvider();
private final CrossReference xref = new CrossReference();
private Context context = new Context();
private Format contextFormat = new ContextOutput(context);
private ContextView contextView = new JFrameContextView().sized(640, 120);
private ContextStepMonitor contextStepMonitor = new ContextStepMonitor(context, contextView, xref.getStepMonitor());
public FirstStories() {
System.setProperty("jbehave.test", "true");
configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(false)
.doIgnoreFailureInView(true).doVerboseFailures(true).useThreads(1).useStoryTimeouts("5m");
configuredEmbedder().useEmbedderControls(new PropertyBasedEmbedderControls());
}
#Test
#Override
public void run() throws Throwable {
Embedder embedder = configuredEmbedder();
try {
embedder.runStoriesAsPaths(storyPaths());
} finally {
embedder.generateCrossReference();
}
}
#Override
public Configuration configuration() {
Properties viewResources = new Properties();
viewResources.put("decorateNonHtml", "true");
viewResources.put("reports", "ftl/jbehave-reports-with-totals.ftl");
return new MostUsefulConfiguration()
.useStoryReporterBuilder(
new StoryReporterBuilder()
.withDefaultFormats()//.withViewResources(viewResources)
.withFormats(contextFormat, CONSOLE, TXT, HTML_TEMPLATE, XML_TEMPLATE).withFailureTrace(true)
.withFailureTraceCompression(true).withCrossReference(xref))
.useStepMonitor(contextStepMonitor);
}
#Override
public InjectableStepsFactory stepsFactory() {
return new InstanceStepsFactory(configuration(), new Steps(dataSourceProvider));
}
private List<String> storyPaths() {
String filter = System.getProperty("story.filter", "**/*.story");
return new StoryFinder().findPaths(codeLocationFromClass(this.getClass()), filter, "**/failing_before*.story");
}
}
The .story file is very straightfoward and only has one scenario:
Meta:
Narrative:
As a user
I want to perform an action
So that I can achieve a business goal
Scenario: Test scenario
Given nothing
When I do nothing
Then nothing happens
The steps file only contains one no-op method just to get everything working properly.
When running both JBehave tests via maven, the first story will run just fine. However, when starting up the second story, the following message appears, and the test shortly fails (I can run the second story on its own without issues, only when it runs after the first story):
WARNING: Failed to load the sqljdbc_auth.dll cause : Native Library C:\Windows\System32\sqljdbc_auth.dll already loaded in another classloader
java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
Is there something I am forgetting to do during my story's run() method to make sure everything is properly destroyed after the story is finished running, so the next story can run correctly without problems?

Adding custom detectors in findbugs

I am trying to add a detector which will detect System.out.println() occurrences. As explained in this post, I've written the detector class, findbugs.xml file and messages.xml file.
I created a jar which contains my detector class, findbugs.xml and messages.xml files. I added this jar in my eclipse environment (window->preferences->java->findbugs->Plugins and misc. Settings). But it is showing invalid entry.
Detector class:
package findbugs.custom.detector;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
import edu.umd.cs.findbugs.bcel.OpcodeStackDetector;
import edu.umd.cs.findbugs.classfile.ClassDescriptor;
import edu.umd.cs.findbugs.classfile.FieldDescriptor;
public class CallToSystemOutPrintlnDetector2 extends OpcodeStackDetector {
private BugReporter bugReporter;
public CallToSystemOutPrintlnDetector2(BugReporter bugReporter) {
super();
this.bugReporter = bugReporter;
}
public void sawOpcode(int seen) {
if (seen == GETSTATIC){
try {
FieldDescriptor operand = getFieldDescriptorOperand();
ClassDescriptor classDescriptor = operand.getClassDescriptor();
if ("java/lang/System".equals(classDescriptor.getClassName()) &&
("err".equals(operand.getName())||"out".equals(operand.getName()))) {
reportBug();
}
} catch (Exception e) {
//ignore
}
}
}
private void reportBug(){
this.bugReporter.reportBug(getBugInstance());
}
private BugInstance getBugInstance() {
return new BugInstance(this, "MY_CALL_TO_SYSTEM_OUT_BUG", 10)
.addClassAndMethod(this)
.addSourceLine(this);
}
}
findbugs.xml file:
<FindbugsPlugin>
<Detector class="findbugs.custom.detector.CallToSystemOutPrintlnDetector2" speed="fast" />
<BugPattern abbrev="SYS_OUT_P" type="CALL_TO_SYSTEM_OUT" category="CORRECTNESS" />
</FindbugsPlugin>
messages.xml file:
<MessageCollection>
<Detector class="findbugs.custom.detector.CallToSystemOutPrintlnDetector2">
<Details>
<![CDATA[
<p>This detector warns about SYS_OUTs used in the code. It is a fast detector.</p>
]]>
</Details>
</Detector>
<BugPattern type="CALL_TO_SYSTEM_OUT_BUG">
<ShortDescription>sysout detector</ShortDescription>
<LongDescription>Found sysout in {1}</LongDescription>
<Details>
<![CDATA[
<p>This is a call to System.out.println/err method. </p>
which should be avoided.
]]>
</Details>
</BugPattern>
<BugCode abbrev="SYS_OUT_P">Found sysout</BugCode>
</MessageCollection>
How can I correct this?
The error is because of the package hierarchy. My detector class was inside findbugs.custom.detector package, but when I created the jar (using eclipse) I was only selecting the required files (findbugs.xml, messages.xml, detector class).
Hence the package information was not included in the jar. Our XML files read the detector class using the attribute class of the Detector tag whose value was findbugs.custom.detector.MyDetectorClass.
So when XML files try to read the detector class, they could not find findbugs.custom.detector package. To build a jar with the package information in it, select the whole project and then create a jar with required files.

Loading stories from classpath (and stories aren't called .story)

I have a multi-module maven project. My story files are in a module of their own, because we have separate gui and api tests driven from them, and a jar is created containing these -- the story files are named *.feature.
In another module I have created a Story class:
public class NewAnnouncements extends JUnitStory {
#Override
public Configuration configuration() {
return new MostUsefulConfiguration().useStoryLoader(new LoadFromClasspath());
}
#Override
public InjectableStepsFactory stepsFactory() {
return new InstanceStepsFactory(configuration(), new NewAnnouncements());
}
}
But, predictably, this does not find its stories. How could it? The stories aren't called *.story and they aren't on the filesystem (though they are in the same classpath). The error I get is:
org.jbehave.core.io.StoryResourceNotFound: Story path 'org/.../announcement/new_announcements.story' not found by class loader sun.misc.Launcher$AppClassLoader#63e68a2b
How do I get jbehave to find my story files? How do I make it understand that they're not called *.story?
Try an example from JBehave documentation with JUnitStories :
http://jbehave.org/reference/stable/configuration.html
public class TraderStories extends JUnitStories {
public TraderStories() {
// configure as TraderStory except for
Configuration configuration = new MostUsefulConfiguration()
.useStoryLoader(new LoadFromURL())
}
#Override
protected List<String> storyPaths() {
String codeLocation = codeLocationFromClass(this.getClass()).getFile();
return new StoryFinder().findPaths(codeLocation, asList("**/trader*.story"),
asList(""), "file:"+codeLocation);
}
and replace in this example the pattern: asList("**/trader*.story") with a pattern: asList("**/*.feature")

save file from unit test to project tree

In the unit tests as a side effect I am creating screenshots for various parts of the GUI.
I want to use these screenshots when compiling the documentation.
Therefore I want to save them to a directory within the source tree.
Is there any reliable way to get the source directory root when running a junit test?
If not, how can I make sure that unit tests run with cwd=project root when using eclipse, and when using maven?
wether you execute tests on eclipse or using maven, if you don't specify a path when you create the file it's automatically created at project root directory.
so if you specify a relative folder your files will go there :
public class TestFileCreation {
#Test
public void testFileCreation() throws IOException {
File f = new File("src/main/resources/hello.txt");
OutputStream ostream = new FileOutputStream(f);
String data = "Hello there !";
ostream.write(data.getBytes());
ostream.close();
}
}
will create a file inside the $PROJECT/src/main/resources.
Hope my answer helps
You can base on your classes location. Proposed solution here is to use class that will surely be in classpath. Then you can use class.getResource(""). Example
public class ResouceRoot {
public static String get() {
String s = ResouceRoot.class.getResource("").toString();
if (s.startsWith("jar:")) {
s = s.replace("jar:", "").replaceAll("!.*", "");
} else {
s = s.replaceAll("classes.*", "classes");
}
File f = new File(s.replace("file:", ""));
return f.getParentFile().getParentFile().getAbsolutePath();
}
public static void main(String[] args) throws IOException {
System.out.println(get());
}
}
(this code will give base dir for netbeans projects if they are launched from netbeans or by java -jar ... )

Categories