Is this a valid use of the java ClassGraph api? - java

Using compile 'io.github.classgraph:classgraph:4.8.65'
https://github.com/classgraph/classgraph/wiki/ClassGraph-API
Java 8
ScanResult scanResult =
new ClassGraph().enableAllInfo()
.whitelistPackages("abc1")
.whitelistPackages("abc2")
.whitelistPackages("java")
.scan();
When I encounter ClassInfo objects for classes from the packages abc1 or abc2 they are able to reference things like java.util.HashMap, I see them in the FieldInfo.
But when I then proceed to do scanResult.getClassInfo("java.util.HashMap"), it returns null.
(following FieldInfos for other classes within the abc1 or abc2 packages do return more ClassInfo objects)
My question is, is it correct to think I would be able to get the ClassInfo objects to the java jre classes via the ClassGraph method chaining as shown above?
Added this test which fails, it surprisingly only prints one class rather than expected dozens:
package abc;
import io.github.classgraph.ScanResult;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ClassInfo;
import java.util.*;
import java.io.*;
import java.util.function.*;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
#SpringJUnitConfig
#SpringBootTest(classes = {})
public class ExamplesSpec {
#org.junit.jupiter.api.Test
#org.junit.jupiter.api.DisplayName(value="test_for_built_in_java_jre_classes")
public void test_on_line_42() throws Exception {
System.out.println("test_for_built_in_java_jre_classes");
ClassInfo found = null;
try (
ScanResult result = new ClassGraph().enableAllInfo().whitelistPackages("java.util").scan()
) {
System.out.println("here all the classes....");
for( ClassInfo item : result.getAllClasses()) {
System.out.println("here classinfo: " + item);
}
found = result.getClassInfo("java.util.HashMap");
}
assert found != null;
}
}
The only class found is this:
here classinfo: public class java.util.zip.VFSZipFile implements java.util.zip.ZipConstants

Found the answer!
In the setup of the ClassGraph, in order to scan the jre provided classes, you would need to add this to the method chaining:
.enableSystemJarsAndModules()
For example:
new ClassGraph().enableAllInfo()
.whitelistPackages("abc1")
.whitelistPackages("abc2")
.whitelistPackages("java")
.enableSystemJarsAndModules()
.scan();
This is detailed in the documentation found here:
https://github.com/classgraph/classgraph/wiki/API:-ClassGraph-Constructor#configuring-the-classgraph-instance

Related

Is it possible to have only 1 implementation of IAnnotationTransformer in a project

Can we have more than 1 implementation of IAnnotationTransformer in a project that is using TestNG?
I'm using TestNg version 7.0.0.
TestNG currently lets you wire in ONLY ONE implementation of IAnnotationTransformer. If you try to plug in multiple ones of them, the last one that got added is what will get invoked.
There's an open issue that is tracking this ask. See GITHUB-1894.
As an alternative you can build your own composite IAnnotationTransformer which can be used to iterate through all the other annotation transformer instances. Here's a sample (Its available in the above mentioned github link)
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import org.testng.IAnnotationTransformer;
import org.testng.annotations.ITestAnnotation;
import org.testng.collections.Lists;
import org.testng.internal.ClassHelper;
public class CompositeTransformer implements IAnnotationTransformer {
private static final String JVM_ARGS =
"com.rationaleemotions.github.issue1894.Listener1, com.rationaleemotions.github.issue1894.Listener2";
private List<IAnnotationTransformer> transformers = Lists.newArrayList();
public CompositeTransformer() {
// Ideally this would get a value from the command line. But just for demo purposes
// I am hard-coding the values.
String listeners = System.getProperty("transformers", JVM_ARGS);
Arrays.stream(listeners.split(","))
.forEach(
each -> {
Class<?> clazz = ClassHelper.forName(each.trim());
IAnnotationTransformer transformer =
(IAnnotationTransformer) ClassHelper.newInstance(clazz);
transformers.add(transformer);
});
}
#Override
public void transform(
ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
for (IAnnotationTransformer each : transformers) {
each.transform(annotation, testClass, testConstructor, testMethod);
}
}
}

TestNG - Read custom annotation details

Requirement: Read custom annotation details and generate report for all test classes of all suites.
Tried Solution:
Implemented custom listener using ITestListener. But don't see direct way to get custom annotation details used as part of test methods apart from below way.
#Override
public void onStart(ITestContext context) {
ITestNGMethod[] testNGMethods = context.getAllTestMethods();
for (ITestNGMethod testNgmethod : testNGMethods) {
Method[] methods = testNgmethod.getRealClass().getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(MyCustomAnnotation.class)) {
//Get required info
}
}
}
}
Inner loop triggers almost n*n(number of methods) times for each test class. I can control it by adding conditions.
As I'm new bee to TestNG framework, would like to know the better solution to achieve my requirement i.e. generating report by reading custom annotation details from all test methods from all suites.
Here's how you do it.
I am using the latest released version of TestNG as of today viz., 7.0.0-beta3 and using Java8 streams
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestNGMethod;
public class MyListener implements ITestListener {
#Override
public void onStart(ITestContext context) {
List<ITestNGMethod> methodsWithCustomAnnotation =
Arrays.stream(context.getAllTestMethods())
.filter(
iTestNGMethod ->
iTestNGMethod
.getConstructorOrMethod()
.getMethod()
.getAnnotation(MyCustomAnnotation.class)
!= null)
.collect(Collectors.toList());
}
#Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
#Target({METHOD, TYPE})
public static #interface MyCustomAnnotation {}
}

How can I prevent Eclipse from supplying deprecated classes when importing?

I have a recurring problem using Eclipse. Consider the following example:
As you can see I've pressed Ctrl+Shift+O. I can choose from a deprecated and a non-deprecated annotation. My problem is that I am often supplied with dozens of classes and half of them are deprecated (a perfect example is the JUnit Assert classes).
My question is how can I make Eclipse ignore all deprecated classes when organizing imports?
Currently Eclipse does not provide such an option... Eclipse Documentation for Organise Imports (Kepler version).
However, with a fudge you can achieve the same result...
Eclipse allows you to provide a list of classes/packages to filter-out.
To do this, navigate to Preferences > Type Filters.
I've done this in my environment to ensure "java.awt.List" is not suggested when I really want "java.util.List".
What you want is to add all deprecated classes to this list.
This list is maintained in your eclipse workspace preferences...
File ... C:\Users\[YOUR_USER_NAME]\workspace\.metadata\.plugins\org.eclipse.core.runtime\.settings\org.eclipse.jdt.ui.prefs
Property ... org.eclipse.jdt.ui.typefilter.enabled=java.awt.List;
All that is required is that you create a list of deprecated classes, and store it in this properties file.
Eclispe can help create this list...
Perform a "Java Search" for "Deprecated".
Then group the results by type.
And copy the results using "Copy Qualified Name"
The results will contain Generics, and this should be removed.
For example, "javafx.scene.control.Cell<T>" should read "javafx.scene.control.Cell".
In addition to containing deprecated classes, the results will also contain any class that has the word "Deprecated". This could be a comment or a method annotation. This list will need to be filtered to retain only deprecated classes.
The script below processes this class list to remove generics, and filtering out classes that are not deprecated (ie, only has method deprecation). The class list is read from a file named "DeprecatedClassList.txt". When it cannot check the class annotation, it skips the class and prints it out (for manual checking).
import java.lang.annotation.Annotation;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ConfigurationGenerator {
public static void main(String[] args) throws Exception {
List<String> cleanedList = Files
.readAllLines(Paths.get("DeprecatedClassList.txt")).stream()
.map(ConfigurationGenerator::removeGenerics)
.filter(ConfigurationGenerator::hasDeprecatedConstructor)
.collect(Collectors.toList());
String propertyName = "org.eclipse.jdt.ui.typefilter.enabled=";
String propertyValue = String.join(";", cleanedList).concat(";");
String configuration = propertyName + propertyValue;
System.out.println("Configuration property...");
System.out.println(configuration);
}
public static String removeGenerics(String className) {
int openingBracket = className.indexOf("<");
if (openingBracket == -1)
return className;
else
return className.substring(0, openingBracket);
}
public static boolean hasDeprecatedConstructor(String className) {
Class theClass = null;
try {
theClass = Class.forName(className);
} catch (Throwable e) {
// Ignore bad results
System.out.println("Skipping: " + className);
return false;
}
Annotation[] annotations = theClass.getAnnotations();
Optional<Annotation> deprecatedConstructor = Stream
.of(annotations)
.filter(annotation -> annotation.toString().equals(
"#java.lang.Deprecated()")).findAny();
return deprecatedConstructor.isPresent();
}
}
There is one problem with this approach though. You may want to use a deprecated class when a non-deprecated version does not exist. You will not see the deprecated class if it has been purposefully hidden. To resolve that, just be sure you exclude them from the filter.

Assert an object is a specific type

Is it possible in JUnit to assert an object is an instance of a class? For various reasons I have an object in my test that I want to check the type of. Is it a type of Object1 or a type of Object2?
Currently I have:
assertTrue(myObject instanceof Object1);
assertTrue(myObject instanceof Object2);
This works but I was wondering if there is a more expressive way of doing this.
For example something like:
assertObjectIsClass(myObject, Object1);
I could do this:
assertEquals(myObject.class, Object1.getClass());
Is there a specific assert method that allows me to test a type of an object in a more elegant, fluid manner?
You can use the assertThat method and the Matchers that comes with JUnit.
Take a look at this link that describes a little bit about the JUnit Matchers.
Example:
public class BaseClass {
}
public class SubClass extends BaseClass {
}
Test:
import org.junit.Test;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertThat;
/**
* #author maba, 2012-09-13
*/
public class InstanceOfTest {
#Test
public void testInstanceOf() {
SubClass subClass = new SubClass();
assertThat(subClass, instanceOf(BaseClass.class));
}
}
Since assertThat which was the old answer is now deprecated, I am posting the correct solution:
assertTrue(objectUnderTest instanceof TargetObject);
Solution for JUnit 5
The documentation says:
However, JUnit Jupiter’s org.junit.jupiter.Assertions class does not provide an assertThat() method like the one found in JUnit 4’s org.junit.Assert class which accepts a Hamcrest Matcher. Instead, developers are encouraged to use the built-in support for matchers provided by third-party assertion libraries.
Example for Hamcrest:
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.MatcherAssert.assertThat;
import org.junit.jupiter.api.Test;
class HamcrestAssertionDemo {
#Test
void assertWithHamcrestMatcher() {
SubClass subClass = new SubClass();
assertThat(subClass, instanceOf(BaseClass.class));
}
}
Example for AssertJ:
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
class AssertJDemo {
#Test
void assertWithAssertJ() {
SubClass subClass = new SubClass();
assertThat(subClass).isInstanceOf(BaseClass.class);
}
}
Note that this assumes you want to test behaviors similar to instanceof (which accepts subclasses). If you want exact equal type, I don’t see a better way than asserting the two class to be equal like you mentioned in the question.
Experimental Solution for JUnit 5.8
In Junit 5.8, the experimental assertInstanceOf() method was added, so you don't need Hamcrest or AssertJ anymore. The solution is now as simple as:
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import org.junit.Test;
public class InstanceOfTest {
#Test
public void testInstanceOf() {
SubClass subClass = new SubClass();
assertInstanceOf(BaseClass.class, subClass);
}
}
Solution for JUnit 5 for Kotlin!
Example for Hamcrest:
import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert
import org.junit.jupiter.api.Test
class HamcrestAssertionDemo {
#Test
fun assertWithHamcrestMatcher() {
val subClass = SubClass()
MatcherAssert.assertThat(subClass, CoreMatchers.instanceOf<Any>(BaseClass::class.java))
}
}
Example for AssertJ:
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
class AssertJDemo {
#Test
fun assertWithAssertJ() {
val subClass = SubClass()
assertThat(subClass).isInstanceOf(BaseClass::class.java)
}
}
Solution for JUnit for Kotlin
What worked for me:
assert(obj is ClassName)
for exmaple
assert(obj is User)
NOTE: assert is coming from AssertionsJVM.kt file

How to get all imports defined in a class using java reflection?

Hi i am new in java reflection domain.So can anyone guide me in this problem scenario.
I have a class named "SomClass.java" and it imports a package named "SomPackage.RefClass" And some other java libraries like java.lang.. etc.
Now i wish to get know all the imports defined in a class through reflection.
import SomPackage.RefClass;
import java.lang.reflect.Field;
import java.io.IOException;
public class SomeClass{
RefClass refClass_Obj;
String nationality;
///some other members
}
I just wanna know the list of all import defined in a class using reflection.
I have seen a Question posted hear similar to my Q but it is not well elaborated so,need some good direction of help.
thanks in advance.
I just wanna know the list of all
import defined in a class using
reflection
You can't because the compiler doesn't put them into the object file. It throws them away. Import is just a shorthand to the compiler.
Imports are a compile-time feature - there's no difference to the compiled code between a version which uses the full name of the type everywhere it's mentioned, a version which imports everything using a *, and a version which imports classes by full name.
If you want to find all the types used within the compiled code, that's a slightly different matter. You may want to look at BCEL as a way of analyzing bytecode.
I think you can use Qdox to get all the imports in a class which is not actually through reflection, but it can serve your purpose :
String fileFullPath = "Your\\java\\ file \\full\\path";
JavaDocBuilder builder = new JavaDocBuilder();
builder.addSource(new FileReader( fileFullPath ));
JavaSource src = builder.getSources()[0];
String[] imports = src.getImports();
for ( String imp : imports )
{
System.out.println(imp);
}
As suggested by #Asraful Haque qdox helps to read imports of java file
Use Maven dependency
<dependency>
<groupId>com.thoughtworks.qdox</groupId>
<artifactId>qdox</artifactId>
<version>2.0.1</version>
</dependency>
Please refer modified version of code
package readimports;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Collection;
import java.util.List;
import com.thoughtworks.qdox.JavaProjectBuilder;
import com.thoughtworks.qdox.model.JavaSource;
public class TestReadAllImport {
public static void main(String[] args) throws FileNotFoundException {
String fileFullPath = "path to java file";
JavaProjectBuilder builder = new JavaProjectBuilder();
builder.addSource(new FileReader( fileFullPath ));
Collection<JavaSource> srcs = builder.getSources();
for(JavaSource src : srcs) {
List<String> imports = src.getImports();
for ( String imp : imports )
{
System.out.println(imp);
}
}
}
}
Thanks for sharing the qdox, I used it to recursively find all imports and find unique packages and unique imports.
<!-- https://mvnrepository.com/artifact/com.thoughtworks.qdox/qdox -->
<dependency>
<groupId>com.thoughtworks.qdox</groupId>
<artifactId>qdox</artifactId>
<version>2.0.3</version>
</dependency>
Using simple recursion to get all packages and imports of the given class.
package test;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import com.thoughtworks.qdox.JavaProjectBuilder;
import com.thoughtworks.qdox.model.JavaSource;
public class ImportsIdentifier {
private static String sysPath ="//<Absolute Path>/src/main/java/";
private static String fileType = ".java";
private static Set<String> importFiles = new HashSet<>();
private static Set<String> packages = new HashSet<>();
public static void main(String[] args) throws FileNotFoundException {
String path = sysPath + "<java file path>";
printImports(path);
System.out.println(importFiles);
System.out.println(packages);
}
private static void printImports(String path) throws FileNotFoundException {
JavaProjectBuilder jp = new JavaProjectBuilder();
jp.addSource(new FileReader(path));
Collection<JavaSource> srcs = jp.getSources();
for (JavaSource src : srcs) {
System.out.println(src.getPackage());
packages.add(src.getPackage().toString());
for(String imprt: src.getImports()) {
if(imprt.startsWith("<filter for any package>")) {
imprt = sysPath+imprt.replaceAll("\\.", "/")+fileType;
if(importFiles.contains(imprt)) {
continue;
}
importFiles.add(imprt);
System.out.println(imprt);
printImports(imprt);
}
}
}
}
}

Categories

Resources