1

I'm trying to create system like @Repository.

I have lots of interfaces like:

@Client(uri = "http://example.com", username = "httpBasicUsername", password = "httpBasicPassword")
public interface RequestRepository {

     @Request(method = Method.POST, uri = "/mono")
     Mono<Response> ex1(Object body);

     @Request(method = Method.POST, uri = "/flux")
     Flux<Response> ex2(Object body);
}

Right now, I'm creating bean with using this function:

@Bean
public RequestRepository requestRepository(WebClient.Builder builder) {
    return (RequestRepository) Proxy.newProxyInstance(
            RequestRepository.class.getClassLoader(),
            new Class[]{RequestRepository.class},
            new MyDynamicInvocationHandler(builder)
    );
}

But I have lots of these interfaces. For every new interface I need to create another bean function. But I don't want to do that.

Is there a way to say spring (spring boot) if there is @Client annotation then create bean like this etc?

Ahmet
  • 48
  • 7
  • 1
    The `BeanFactoryPostProcessor` interface can be used to create beans dynamically based on some conditions. You can use it in your case. To make things easy I'll suggest to put all your classes in the same package. – akuma8 Jan 06 '21 at 11:41
  • First of all thank you. I had to create custom insterface scanner and register the my proxy in there. I'm new all these bean and proxy stuff, so thanks again. – Ahmet Jan 06 '21 at 13:08

1 Answers1

1

I've solved with creating custom interface scanner.

For more details: https://stackoverflow.com/a/43651431/6841566

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import({InterfaceScanner.class})
public @interface InterfaceScan {
    String[] value() default {};
}

public class InterfaceScanner implements ImportBeanDefinitionRegistrar, EnvironmentAware {
    private Environment environment;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(InterfaceScan.class.getCanonicalName());
        if (annotationAttributes != null) {
            String[] basePackages = (String[]) annotationAttributes.get("value");
            if (basePackages.length == 0)
                basePackages = new String[]{((StandardAnnotationMetadata) metadata)
                        .getIntrospectedClass().getPackage().getName()};

            ClassPathScanningCandidateComponentProvider provider =
                    new ClassPathScanningCandidateComponentProvider(false, environment) {
                        @Override
                        protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                            AnnotationMetadata meta = beanDefinition.getMetadata();
                            return meta.isIndependent() && meta.isInterface();
                        }
                    };
            provider.addIncludeFilter(new AnnotationTypeFilter(Client.class));
            for (String basePackage : basePackages)
                for (BeanDefinition beanDefinition : provider.findCandidateComponents(basePackage))
                    registry.registerBeanDefinition(
                            generateName(beanDefinition.getBeanClassName()),
                            getProxyBeanDefinition(beanDefinition.getBeanClassName()));
        }
    }
}

@InterfaceScan
@SpringBootApplication
public class ExampleApplication {
    ...
}
Ahmet
  • 48
  • 7