How to make Intellij detect Spring beans defined in generic parent class - java

I have a lot of code looking like this
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class ConfigurationBase<T>
{
public #Bean(name="S1") T getS1() { return null; }
public #Bean(name="S2") T getS2() { return null; }
}
And a derived class looking like this:
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
public class ConfigurationDerived extends ConfigurationBase<String>
{
#Override
public String getS1() { return "S1+++"; }
public #Bean(name="S3") String getS3() { return "S3"; }
public #Bean(name="ID") String getCompositeName(
#Qualifier("S1") String s1,
#Qualifier("S2") String s2,
#Qualifier("S3") String s3)
{
return "hello!";
}
}
When the base class is not generic, IntelliJ is able to find all the Spring dependencies.
But when as in this example, the base class is generic, it can't find the beans defined in the base class
For example here, it won't find the beans "S1" and "S2"
Is there a work around?

Related

How do I convert this test rule to JUnit5?

I have some custom rule using junit4 which I would like to convert to junit5. However I'm not able to find good documentation on migrating a MethodRule implementation other than that I should be using junit5 extension instead of rule.
public class MyRule implements MethodRule {
private static final Logger LOGGER = LoggerFactory.getLogger(MyRule.class);
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface MyAnnotation { }
#Override
public Statement apply(final Statement statement, final FrameworkMethod frameworkMethod, final Object o) {
Statement result = statement;
if (hasMyAnnotation(frameworkMethod)) {
result = new Statement() {
#Override
public void evaluate() {
LOGGER.info("Skipping test");
}
};
}
}
return result;
}
private static boolean hasMyAnnotation(final Annotatable frameworkMethod) {
return frameworkMethod.getAnnotation(MyAnnotation.class) != null;
}
My class is using junit4 Statement, FrameworkMethod etc to find out if my method has an annotation... then to skip it. How can I convert this?
Solution 1, Disable test with custom annotation
JUnit 5 provides a type of extension that can control whether or not a test should be run. This is defined by implementing the ExecutionCondition interface.
Extension implementation:
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
import org.junit.jupiter.api.extension.ExecutionCondition;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.platform.commons.logging.Logger;
import org.junit.platform.commons.logging.LoggerFactory;
import org.junit.platform.commons.util.AnnotationUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
public class SkipConditionExtension implements ExecutionCondition {
private static final Logger LOGGER = LoggerFactory.getLogger(SkipConditionExtension.class);
#Override
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
AnnotatedElement element = context.getElement().orElse(null);
if (hasMyAnnotation(element, MyAnnotation.class)) {
LOGGER.info(() ->"Skipping test");
return ConditionEvaluationResult.disabled(String.format("Skipped test: %s by #MyAnnotation", element));
}
return ConditionEvaluationResult.enabled("Test enabled");
}
private <T extends Annotation> boolean hasMyAnnotation(final AnnotatedElement element, Class<T> annotation) {
return element != null && AnnotationUtils.findAnnotation(element, annotation).isPresent();
}
}
Registring extenssion:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
#ExtendWith(SkipConditionExtension.class)
public class TestObject {
#Test
public void test1() {
}
#Test
#MyAnnotation
public void test2() {
}
}
Output:
INFO: Skipping test
Skipped test: public void com.test.TestObject.test2() by #MyAnnotation
Solution 2, Skip test via invocation interseptor
InvocationInterceptor iterface defines the API for Extensions that wish to intercept calls to test.
Current implementation will behave exactly like your previous Rule.
Extension implementation:
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.InvocationInterceptor;
import org.junit.jupiter.api.extension.ReflectiveInvocationContext;
import org.junit.platform.commons.logging.Logger;
import org.junit.platform.commons.logging.LoggerFactory;
import org.junit.platform.commons.util.AnnotationUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
public class SkipCondition implements InvocationInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(SkipConditionExtension.class);
#Override
public void interceptTestMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
AnnotatedElement element = extensionContext.getElement().orElse(null);
if (hasMyAnnotation(element, MyAnnotation.class)) {
LOGGER.info(() ->"Skipping test");
invocation.skip();
} else {
invocation.proceed();
}
}
private <T extends Annotation> boolean hasMyAnnotation(final AnnotatedElement element, Class<T> annotation) {
return element != null && AnnotationUtils.findAnnotation(element, annotation).isPresent();
}
}
Registring extenssion:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
#ExtendWith(SkipCondition.class)
public class TestObject {
#Test
public void test1() {
}
#Test
#MyAnnotation
public void test2() {
}
}
Please note, you can perform automatic extension registration according to documentation.

How to create bean with custom BeanName in Spring?

Problem
There is a Processor class which processes something based on its typesToProcess:
import org.springframework.stereotype.Component;
#Component
public class Processor {
private String typesToProcess;
public Processor(String typesToProcess) {
this.typesToProcess = typesToProcess;
}
public void process(String type) {
if (typesToProcess.equals(type)) {
// process
}
}
}
I need to create some Processor instances to work at different places. The problem is I don't know how many Processor instances should be created when the Spring Application is bootstrapping, as well as their 'typesToProcess'. Further more, the number of Processor instances might change when the application is running. I need to read the types from some configuration file which is stored in database periodically.
Attempts
One way to solve this problem I can thing out is using typesToProcess + Processor as the bean name, though I know it wont work. Is there any other way?
import com.meituan.picture.selection.processor.impl.Processor;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class ProcessorContainer implements ApplicationContextAware {
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public Processor getProcessor(String type) {
String realBeanName = "processor" + type;
// obviouslly this wont work
return applicationContext.getBean(realBeanName, Processor.class);
}
}
I solved similar kind of problem by specifying scope of my bean as prototype without using bean name. Below example explains my implementation:
Create your Processor class as shown below:
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import lombok.Getter;
import lombok.Setter;
#Component
#Getter
#Setter
#Scope("prototype")
public class Processor {
private String typesToProcess;
public Processor(String typesToProcess) {
this.typesToProcess = typesToProcess;
}
public void process(String type) {
if (typesToProcess.equals(type)) {
// process
}
}
}
Implement ApplicationContextAware to generate beans at runtime:
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
#Service
public class ApplicationContextAwareImpl implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) {
ApplicationContextAwareImpl.initApplicationContext(applicationContext);
}
private static void initApplicationContext(ApplicationContext applicationContext) {
ApplicationContextAwareImpl.context = applicationContext;
}
public static <T> T getBean(Class<T> requiredType) {
return context.getBean(requiredType);
}
public static Processor getProcessor(String typesToProcess) {
Processor processor = ApplicationContextAwareImpl.getBean(Processor.class);
processor.setTypesToProcess(typesToProcess);
return processor;
}
}
Use ApplicationContextAwareImpl.getProcessor() method to generate beans programmatically:
Processor type1Processor = ApplicationContextAwareImpl.getProcessor("type1");

Why class name is same as class used in import statement

Below snippet of code is from ITDIAgentException.java file
Can some one help me understand "why class name is same as class used in import statement"(ITDIAgentException)
import com.ibm.di.entry.Entry;
import com.ibm.di.exception.ITDIAgentException;
public class ITDIAgentException extends Exception {
private Entry entry = null;
public ITDIAgentException(String paramString) { super(paramString); }
public Entry getEntry() { return this.entry; }
public void setEntry(Entry paramEntry) { this.entry = paramEntry; }
}
EDIT
You have ITDIAgentException twice: Once in the import statement, and once in the class definition. You are not allowed to have both (would create a namespace clash in the code), but you can access com.ibm.di.exception.ITDIAgentException (assuming that it is different from the class you are creating) by using the full package and class name.
import com.ibm.di.exception.ITDIAgentException;
public class ITDIAgentException extends Exception {

Create custom method level annotation only available to specific return types [AOP]

I want to create an annotation which is only available to a specific type of return values.
For example this is my annotation.
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
public #interface MyAnnotation {
}
I also have an interface:
public interface MyInterface {
String generateKey();
}
An example class that implements my interface:
public class ExampleClass implements MyInterface {
#Override
public String generateKey() {
return "Whatever";
}
}
So after these, I want to configure my annotation in a way that it won't even compile if the return type is not implementing MyInterface.
In this case, I expect this to compile fine:
#MyAnnotation
public ExampleClass anExampleMethod() {
return new ExampleClass();
}
And this to not compile:
#MyAnnotation
public String anotherMethod() {
return "Whatever";
}
I wonder if this is possible in any way. Sure I can check if the parameters implements this interface in my Aspect class but it would be better to have this kind of protection in my library in order to prevent misuse of any annotation.
Helper classer:
These are directly from your example, just with package names and imports.
package de.scrum_master.app;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Retention(RUNTIME)
#Target(METHOD)
public #interface MyAnnotation {}
package de.scrum_master.app;
public interface MyInterface {
String generateKey();
}
package de.scrum_master.app;
public class ExampleClass implements MyInterface {
#Override
public String generateKey() {
return "Whatever";
}
}
Class which should not compile:
This class has some annotated and some non-annotated methods. One annotated method does not return MyInterface or any of its implementing classes. The goal is to fail compilation.
package de.scrum_master.app;
public class Application {
#MyAnnotation
public MyInterface annotatedMethodReturningInterface(int number) {
return new ExampleClass();
}
#MyAnnotation
public ExampleClass annotatedMethodReturningImplementingClass() {
return new ExampleClass();
}
#MyAnnotation
public String annotatedMethodReturningSomethingElse() {
// This one should not compile!
return "Whatever";
}
public MyInterface nonAnnotatedMethodReturningInterface(int number) {
return new ExampleClass();
}
public ExampleClass nonAnnotatedMethodReturningImplementingClass() {
return new ExampleClass();
}
public String nonAnnotatedMethodReturningSomethingElse() {
return "Whatever";
}
}
Convention-checking aspect (native AspectJ syntax):
package de.scrum_master.aspect;
import de.scrum_master.app.MyAnnotation;
import de.scrum_master.app.MyInterface;
public aspect AnnotationCheckerAspect {
declare error :
#annotation(MyAnnotation) && execution(* *(..)) && !execution(MyInterface+ *(..)) :
"Method annotated with #MyAnnotation must return MyInterface type";
}
This aspect checks for
all method executions
where the method has #MyAnnotation
but where the return type is different from MyInterface or any subtype or implementing class.
This is what the result looks like in Eclipse:
Of course the compilation error is just the same if you compile from command line or via AspectJ Maven plugin or similar.
If you do not like native syntax (I prefer it but for some incomprehensible reason other people seem to prefer #AspectJ style):
Convention-checking aspect (annotation-based #AspectJ syntax):
package de.scrum_master.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareError;
#Aspect
public class AnnotationCheckerAspect {
#DeclareError(
"#annotation(de.scrum_master.app.MyAnnotation) && " +
"execution(* *(..)) && " +
"!execution(de.scrum_master.app.MyInterface+ *(..))"
)
static final String wrongSignatureError =
"Method annotated with #MyAnnotation must return MyInterface type";
}
See also my related answers here:
https://stackoverflow.com/a/27121947/1082681
https://stackoverflow.com/a/54067850/1082681
https://stackoverflow.com/a/41700647/1082681
https://stackoverflow.com/a/27312472/1082681
https://stackoverflow.com/a/50126576/1082681

How do I disable a test from running in a subclass in TestNG?

(Update: After I reported this, the TestNG team confirmed the bug.)
Normally, ignoring a class can be done with #Ignore or enabled=false
This does not work on a subclass where test methods are defined in its superclass (and where the subclass defines its specific functionality in hook methods). See ChildClassTest below.
Note that #Ignore is specific to JUnit whereas TestNG uses enabled.
Base class
import org.testng.annotations.Test;
public class ParentClassTest {
#Test
public void test1() {
hook();
}
protected void hook() {};
}
Child class
import org.testng.Reporter;
import org.testng.annotations.Ignore;
#Ignore
public class ChildClassTest extends ParentClassTest {
#Override
protected void hook() {
Reporter.log("ChildClassTest#hook()");
}
}
Been doing some brainstorming out of curiosity, and came up with the workarounds below tested with v6.14.2. I personally prefer the first one, being cleaner, more elegant, flexible and easier to maintain and extend.
context
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
public class MyTest {
#Test
public void shouldRun() {
assertTrue(true);
}
#Test
public void shouldNotRun() {
assertTrue(true);
}
#Test
public void shouldNotRunEither() {
assertTrue(true);
}
}
1) Using listeners - create a TestListenerAdapter & annotation to skip methods with certain names: flexible, clear, easy to reuse and identify for removal. The only downside is that you have to pay attention to method names for typos.
Annotation
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE})
public #interface SkipMethods {
String[] value() default {};
}
TestListenerAdapter
import org.testng.ITestResult;
import org.testng.SkipException;
import org.testng.TestListenerAdapter;
public class TestSkippingListener extends TestListenerAdapter {
#Override
public void onTestStart(ITestResult result) {
// get the skip annotation
SkipMethods skipAnnotation = result.getMethod().getInstance().getClass().getAnnotation(SkipMethods.class);
// if the annotation exists
if (skipAnnotation != null) {
for (String skippableMethod : skipAnnotation.value()) {
// and defines the current method as skippable
if (skippableMethod.equals(result.getMethod().getMethodName())) {
// skip it
throw new SkipException("Method [" + skippableMethod + "] marked for skipping");
}
}
}
}
}
Test Subclass
import org.testng.annotations.Listeners;
// use listener
#Listeners(TestSkippingListener.class)
// define what methods to skip
#SkipMethods({"shouldNotRun", "shouldNotRunEither"})
public class MyTestSkippingInheritedMethods extends MyTest {
}
Result
2) Override methods from superclass and throw SkipException: pretty clear, no possibility of typo, but not reusable, not easily maintainable & introduces useless code:
import org.testng.SkipException;
public class MyTestSkippingInheritedMethods extends MyTest {
#Override
public void shouldNotRun() {
throw new SkipException("Skipped");
}
#Override
public void shouldNotRunEither() {
throw new SkipException("Skipped");
}
}
Result

Categories