I am creating a spring-boot-starter kafka streams library.
In that I am defining a configuration class which will have a list of storeBuilders.
class CustomConfiguration {
private String A;
private String B;
private Set<StoreBuilder<?>> transformationStoreBuilders;
private Set<StoreBuilder<?>> processorStoreBuilders;
// Constructor and Getter
}
The client which will import this spring-boot-starter library will have to create a bean of the above configuration class.
Now I am creating a custom TransformerSupplier and I want to auto-set the stores by autowiring stores from CustomConfiguration.
I am doing something like this:
public abstract class CustomTransformerSupplier<A, B, C, D> implements TransformerSupplier<A, B, KeyValue<C, D>> {
#Autowired
private CustomConfiguration configuration;
public abstract CustomTransformer<A, B, KeyValue<C, D>> get();
public Set<StoreBuilder<?>> stores() {
return configuration.getTransformationStoreBuilders();
}
}
However the CustomTransformerSupplier bean will be created by the client and we cannot Autowire bean in a non Bean class.
How do I auto set the store builders in the transformer supplier?
Why am I following the approach mentioned is because:
The client can have n store builders
There is going to be a ProcessorSupplier and a TransformerSupplier. They can share common state stores.
I want the client to just create the state stores and not worry about injecting the state stores in the TransformerSupplier and the processorSupplier.
Thanks in advance!
See if #Configurable may answer to your question: https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-atconfigurable
I want to exclude all unused configurations in a Spring boot application. The problem is that I do not know which one are used and which are not.
Is it possible to get in run time all configurations which are used in a Spring boot application and to write them into a file which is read from #EnableAutoConfiguration exclude annotation? If it is no is there another approach to do something like this?
I personnally believe you should to go along with Spring-Boot since most (if not all) autoconfigurations are only enabled when some class(es) is found on the classpath.
#Import the Autoconfiguration classes yourself
I don't know if it's a great idea, but still you could skip the AutoConfiguration altogether by not using #SpringBootApplication and/or #EnableAutoConfiguration.
Instead, define your Spring Boot entry point like a normal bean with #ComponentScan AND #import the Autoconfiguration classes of your choice:
#ComponentScan(excludeFilters = #Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))
#Import({EmbeddedServletContainerAutoConfiguration.class})
public class Launcher {
public static void main(String[] args) {
SpringApplication.run(Launcher.class, args);
}
}
Instead of having AutoConfiguration kickstart the configurations (based on #Conditional presence of some classes on the classpath), you can import the one you want.
Something like this would get you going (for a minimal web container):
#Import({EmbeddedServletContainerAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
ConfigurationPropertiesAutoConfiguration.class,
ServerPropertiesAutoConfiguration.class,
WebMvcAutoConfiguration.class,
MessageSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class})
Note that this may easily lead you to have some basic functionalities disabled until you realize it and add its AutoConfiguration.
You'll find the list of AutoConfiguration classes in spring-boot-autoconfigure-xxx.jar/META-INF/spring.factories:
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.hornetq.HornetQAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\
org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\
org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\
org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.velocity.VelocityAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration
# Template availability providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.velocity.VelocityTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.web.JspTemplateAvailabilityProvider
I am facing some problems with kotlin in conjunction with spring.
I have a controller bean (without an interface btw) which has an auto-wired service bean via the primary constructor.
It works perfectly unless I use caching annotations for the controller. Apparently springs caching generates a proxy class under the hood which deals with the caching.
My code looks like this:
#RestController
#RequestMapping("/regions/")
open class RegionController #Autowired constructor(val service: RegionService) {
#RequestMapping("{id}", method = arrayOf(RequestMethod.GET))
#Cacheable(cacheNames = arrayOf("regions"))
fun get(#PathVariable id: Long): RegionResource {
return this.service.get(id)
}
}
The problem now is a null pointer exception when the method is executed, actually this.service is null which technically is not possible as it is a nonnull variable in kotlin.
I assume that class proxies generated by spring initialize the class with null values instead of the autowired bean. This must be a common pitfall using kotlin and spring. How did you circumvent this problem?
In Kotlin both classes and members are final by default.
For the proxying library (CGLIB, javaassist) to be able to proxy a method it has to be declared non final and in a non final class (since those libraries implement proxying by subclassing). Change your controller method to:
#RequestMapping("{id}", method = arrayOf(RequestMethod.GET))
#Cacheable(cacheNames = arrayOf("regions"))
open fun get(#PathVariable id: Long): RegionResource {
return this.service.get(id)
}
You probably see a warning in console regarding RegionController methods not being subject to proxying.
The Kotlin compiler plugin
The Kotlin team has acknowledged this difficulty and created a plugin that marks the standard AOP proxy candidates e.g. #Component with open.
You can enable the plugin by in your build.gradle:
plugins {
id "org.jetbrains.kotlin.plugin.spring" version "1.1.60"
}
Soon this might not be a problem any longer.
There is work in progress that any lib (including spring for example) can specify a list of annotations a file in META-INF. Once a class is annotated with one of these, it will default to open for the class itself and all its functions. This is also true for classes inheriting from an annotated class.
For more details, have a look at https://github.com/Kotlin/KEEP/pull/40#issuecomment-250773204
I have created my own annotation for classes: #MyAnnotation, and have annotated two classes with it.
I have also annotated a few methods in these classes with Spring's #Transactional. According to the Spring documentation for Transaction Management, the bean factory actually wraps my class into a proxy.
Last, I use the following code to retrieve the annotated beans.
Method getBeansWithAnnotation correctly returns my declared beans. Good.
The class of the bean is actually a proxy class generated by Spring. Good, this means the #Transactional attribute is found and works.
Method findAnnotation does not find MyAnnotation in the bean. Bad. I wish I could read this annotation from the actual classes or proxies seamlessly.
If a bean is a proxy, how can I find the annotations on the actual class ?
What should I be using instead of AnnotationUtils.findAnnotation() for the desired result ?
Map<String,Object> beans = ctx.getBeansWithAnnotation(MyAnnotation.class);
System.out.println(beans.size());
// prints 2. ok !
for (Object bean: services.values()) {
System.out.println(bean.getClass());
// $Proxy
MyAnnotation annotation = AnnotationUtils.findAnnotation(svc.getClass(), MyAnnotation.class);
//
// Problem ! annotation is null !
//
}
You can find the real class of the proxied bean by calling AopProxyUtils.ultimateTargetClass.
Determine
the ultimate target class of the given bean instance, traversing not
only a top-level proxy but any number of nested proxies as well - as
long as possible without side effects, that is, just for singleton
targets.
The solution is not to work on the bean itself, but to ask the application context instead.
Use method ApplicationContext#findAnnotationOnBean(String,Class).
Map<String,Object> beans = ctx.getBeansWithAnnotation(MyAnnotation.class);
System.out.println(beans.size());
// prints 2. ok !
for (Object bean: services.values()) {
System.out.println(bean.getClass());
// $Proxy
/* MyAnnotation annotation = AnnotationUtils.findAnnotation(svc.getClass(), MyAnnotation.class);
// Problem ! annotation is null !
*/
MyAnnotation annotation = ctx.findAnnotationOnBean(beanName, MyAnnotation.class);
// Yay ! Correct !
}
does exist a specific annotation to define the address of the endpoint.
In fact, I want to remove the attribute address in the SPring file and move the annotation directly in the impl. class.
Current:
jaxws:endpoint id="dataManagerEndPoint" implementor="#dataManagerService" address="/datamanager/v1.0"
#WebService
public interface DataManagerService
I would like to change to (if possible) ...
jaxws:endpoint id="dataManagerEndPoint" implementor="#dataManagerService"
#WebService
#EndPointAddress ("/datamanager/v1.0")
public interface DataManagerService
Many thanks, in advance,
Christophe P.
#WebService(portName = "PortTypeName", serviceName = "ServiceName", targetNamespace = "http://www.namespace.com", wsdlLocation = "META-INF/wsdlname.wsdl", endpointInterface = "com.package.service.PortTypeName")