Spring boot - adding a filter - filter

I am wondering how I can add a filter in spring boot if the java class is only available in the app container ie it is not available at compile time.
FilterRegistrationBean can only add a Filter class and not a String of a class name that will get instantiated at run time.
Is this possible? I think I might have to add a web.xml to my project but I would prefer not to at the minute.
Any help appreciated.
Thanks.

If your Filter has a no-args constructor this should work.
try {
Class c = Class.forName("com.runtimeFilter");
Filter filter = (Filter)c.newInstance();
//register filter with bean
} catch (Exception e) {}
If it has a constructor with args you need to use the getConstructor() method on Class.

Related

intercept request start and end in Vaadin 14 (Flow) with Spring Boot

I'm using vaadin-spring-boot-starter for integration of Vaadin Framework 14 and Spring Boot.
I would like to override the requestStart and requestEnd methods of the SpringServlet class to do the following things:
put stuff such as the current route / view path and current user ID into the SLF4J MDC in order to include it in each logging statement
log the duration of the request
In Vaadin 8 there was a SpringVaadinServlet class which I could replace by simply annotating my custom subclass with #SpringComponent("vaadinServlet").
This approach no longer works. The vaadin-spring integration contains SpringBootConfiguration which contains a direct call to the SpringServlet constructor:
#Bean
public ServletRegistrationBean<SpringServlet> servletRegistrationBean() {
String mapping = configurationProperties.getUrlMapping();
Map<String, String> initParameters = new HashMap<>();
boolean rootMapping = RootMappedCondition.isRootMapping(mapping);
if (rootMapping) {
mapping = VaadinServletConfiguration.VAADIN_SERVLET_MAPPING;
initParameters.put(Constants.SERVLET_PARAMETER_PUSH_URL,
VaadinMVCWebAppInitializer
.makeContextRelative(mapping.replace("*", "")));
}
ServletRegistrationBean<SpringServlet> registration = new ServletRegistrationBean<>(
new SpringServlet(context, rootMapping), mapping); // <-- HERE
registration.setInitParameters(initParameters);
registration.setAsyncSupported(configurationProperties.isAsyncSupported());
registration.setName(
ClassUtils.getShortNameAsProperty(SpringServlet.class));
return registration;
}
They should use a conditional bean here so we could replace it, but unfortunately they're not.
Just adding a custom ServletRegistrationBean with a copy of the above code (but the constructor call substituted with my own) doesn't work, even with #Primary.
So is there a better way to do what I want than to exclude the whole vaadin-spring autoconfiguration and copy everything in my own configuration bean? It works but I have to check if everything's still OK after each vaadin-spring upgrade.
You could add a VaadinServiceInitListener through which you can add a custom request handler. Alternatively you could use a Filter.

Creating Spring beans dynamically runtime using method

I have to use company's custom made libraries with Spring Boot and wondering if I'm able to create bean like this in runtime and add it to Spring application context.
#Bean(name = {"customConnectionFactory"})
public ConnFactory connector() {
return new SimpleConnFactory(configuration(), "prefix");
}
So this worked fine when I was allowed to wire beans normally when starting the application. Now requirements have changed and I should be able to do this dynamically runtime. I've done some research and it seems that it's possible to add class to spring context runtime, but how about running method which returns new object?
Could be something like this
DefaultListableBeanFactory beanFactory = //get and store the factory somewhere
MyBean newBean = new MyBean();
beanFactory.initializeBean(newBean,"TheBeanName"); //could be class' canonical name
beanFactory.autowireBeanProperties(newBean, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
beanFactory.registerSingleton("TheBeanName", newBean);

Spring - Retrieve all scanned packages

I'm creating a Spring Starter project and need to get all classes which are marked with a custom annotation. The annotated class is not a spring bean.
My current solution is to use the ClassPathScanningCandidateComponentProvider to find the required classes.
ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(CustomAnnotation.class));
candidates = scanner.findCandidateComponents("THE MISSING PACKAGE NAME");
The problem is that I'm currently provide an empty package String so that all packages/classes are scanned which slows the startup down.
I need to access the packages which are scanned by Spring to avoid the scanning of all packages and classes.
Is there a way to retrieve all packages programmatically which are scanned by Spring or is there an alternative solution to retrieve custom annotated classes which are not Spring beans.
Greets
One solution without the need to make a full classpath scan is to use the AutowiredAnnotationBeanPostProcessor:
private List<Class<?>> candidates = new ArrayList<>();
#Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if(beanClass.isAnnotationPresent(YourAnnotation.class)){
candiates.add(beanClass));
System.out.println(beanClass);
return new Object();
}
}
#Bean
public CandiateHolder candidates() {
return new CandidateHolder(candidates);
}
You can check if the bean class which should be instantiated has the required annotation. If its the case you add the class to a property to expose it later as a bean. Instead of returning null you have to return an instance of a new Object. The returned object can be used to wrap the class in a proxy. Cause I don't need an instance I will return a simple new object. Its maybe a dirty hack but it works.
I have to use this kind of hack cause an instantiation of the needed object will result in an runtime error cause it has to be instantiated in the framework I use.

Spring-Wicket: Bean Injection with Resource

I am writing tests for my wicket-application and need to inject a Spring Bean into a page (done by annotation) to do this.
Consider following code:
protected void setUp() {
tester = new WicketTester();
scanService = new ScanService();
ApplicationContextMock appctx=new ApplicationContextMock();
appctx.putBean("pxGenericService", new PxGenericServiceImpl());
tester.getApplication().getComponentInstantiationListeners().add(new SpringComponentInjector(tester.getApplication(), appctx));
}
This actually seem to work (no nullpointer). The problem is: the bean got a resource (variable with #Resource annotation) and when I run the test on the page, this resource turns out to be null (nullpointer exception). How do I fix this problem?
You also have to add an instance of all dependencies your bean has to the mock application context. So add an instance of the class PxGenericServiceImpl uses to appctx.
I don't think that SpringComponentInjector supports #Resource. The only supported annotations are #SpringBean and #Inject. See AnnotProxyFieldValueFactory:
#Override
public boolean supportsField(final Field field)
{
return field.isAnnotationPresent(SpringBean.class) || field.isAnnotationPresent(Inject.class);
}

Grails Dependency Injection Outside of Services?

I have a Grails application that needs to run a strategy that will likely be swapped out over time. I know Spring underlies Grails, so I was wondering if I had access to Spring's IoC container so that I could externalize the actual dependency in an xml file (note: I have never actually done this, but just know of it, so I may be missing something). My goal is to be able to do something like the following:
class SchemaUpdateService {
public int calculateSomething(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
IStrategy strat = (IStrategy) ctx.getBean("mystrat");
}
}
And then map the appropriate implementation in the beans.xml file. I assume this is supported in Grails. Does anyone have any documentation on how this would work? Do I really just need the Spring IoC library and it will just work? Thanks!
You define your beans in resources.xml or resources.groovy. The grails documentation is very clear about how to access the Spring application context.
You can access the application context from any Grails artefact using
ApplicationContext ctx = grailsApplication.mainContext
You can then use this to retrieve whichever beans you're interested in:
IStrategy strat = (IStrategy) ctx.getBean("mystrat")
In classes that don't have access to grailsApplication, you could use a helper such as the following to access the application context and the beans therein
class SpringUtils {
static getBean(String name) {
applicationContext.getBean(name)
}
static <T> T getBean(String name, Class<T> requiredType) {
applicationContext.getBean(name, requiredType)
}
static ApplicationContext getApplicationContext() {
ApplicationHolder.application.mainContext
}
}
However, this should only be necessary if you need to retrieve different implementations of the same bean at runtime. If the required bean is known at compile-time, just wire the beans together in resources.xml or resources.groovy
First of all, you want to define your strategy in your grails-app/conf/spring/resources.groovy:
beans = {
myStrat(com.yourcompany.StrategyImpl) {
someProperty = someValue
}
}
Then, you simply def the a property with the same name into your service:
class SomeGrailsService {
def myStrat
def someMethod() {
return myStrat.doSomething()
}
}
In any Grails artefact (such as services and domain classes), Grails will automatically give the myStrat property the correct value. But don't forget, in a unit test you'll have to give it a value manually as the auto-wiring does not happen in unit tests.
Outside of a Grails artefact, you can use something like:
def myStrat = ApplicationHolder.application.mainContext.myStrat
In Grails 2.0, Graeme et al are deprecating the use of the *Holder classes (such as ApplicationHolder and ConfigurationHolder), so I'm not quite sure what the Grails 2.0 approach would be...

Resources