Ahmet
Ahmet

Reputation: 48

Create Bean for interface

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?

Upvotes: 1

Views: 3811

Answers (1)

Ahmet
Ahmet

Reputation: 48

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 {
    ...
}

Upvotes: 1

Related Questions