I am writing a Servlet Filter and would like to use one of my Liferay components using #Reference:
package my.filter;
import my.Compo;
import org.osgi.service.component.annotations.Reference;
public class MyFilter implements Filter {
#Override
public void doFilter(...) {
compo.doTheThing();
}
#Reference(unbind = "-")
protected my.Compo compo;
}
I get this Java compilation error:
annotation type not applicable to this kind of declaration
What am I doing wrong?
Is it maybe impossible to achieve this?
As tipped by Miroslav, #Reference can only be used in an OSGi component, and a servlet filter is not one.
The solution in Liferay 7 is to develop a filter component.
The procedure to do so is explained at http://www.javasavvy.com/liferay-dxp-filter-tutorial/
You can make a simple filer like: https://www.e-systems.tech/blog/-/blogs/filters-in-liferay-7 and http://www.javasavvy.com/liferay-dxp-filter-tutorial/
But you can also use regular filters, as long you configure you Liferay webapp for that -> there are two consequences if you use regular filters though: you will be out of osgi application and you will have to keep track of this whenever you update your bundle. That is why you should not go with regular implementation. (just complementing the OP answer with the underlining reason to avoid the initial track)
Related
We have several implementations that use the same code base but we want them to do different things: i.e. rest access, administration via rest, indexing, archiving, and queue based.
In our infrastructure build out we want certain things to be accessible but other things not to be, such as in our administration/rest/indexing and archiving we don't want to buildout threads to monitor and handle queue requests, or in our indexing and archiving we want those processes, but we don't want the rest or queue build out.
So, I was wondering if there is a way to "extend" #ConditionalOnExpression with like an #ConditionalOnRest that extends #ConditionalOnExpression so we don't have to include the expression on each Component/RestController which we may have to change in a bunch of places or could be screwed up because it is functionally compile time checked and DRY.
You can achieve this in two ways.
Custom Annotation
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#ConditionalOnExpression() // add your expression
public #interface ConditionalOnRest {
}
Custom Condition
class RestCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return // Your condition logic here
}
}
Then you use it as follows:
#Conditional(RestCondition.class)
In my Spring Boot app, I have events that should be reported in various ways, depending on the environment.
I defined interface IReporter and several implementations, namely LogReporter, EmailReporter, RpcReporter. Also new implementations may appear in future.
Now I want my events to be reported using a subset of reporters. The subset must be specified in the app configuration as the following (for example):
events.reporters=LogReporter,EmailReporter
or
events.reporters=${EVENT_REPORTERS}
or something similar.
As a result, I would like the component that handles events (say class EventHandler) to have magically injected List<IReporter> myReporters containing only the necessary implementations.
And, of course, if a new implementation is created, the only thing to update must be the app configuration (not the code of EventHandler).
I'm familiar with injecting all available implementations, only a #Primary implementation, or a specific one picked with #Qualifier. But looks like these do not solve my problem.
class EventHandler {
#Value("${events.reporter}")
List<String> requiredImplementation;
#Autowired
List<IReporter> myReporters;
public List<IReporter> getRequiredImplementation() {
return myReporters.stream()
.filter(reporter -> requiredImplementation.contains(reporter.getClass().getSimpleName()))
.collect(Collectors.toList());
}
}
EDIT:
One option I could think if we want framework to autowire only the required beans, we can explore #ConditionalOnExpression.
For instance:
#Component
#ConditionalOnExpression("#{'${events.reporter}'.contains('LogReporter')}")
Class LogReporter {
}
#Component
#ConditionalOnExpression("#{'${events.reporter}'.contains('EmailReporter')}")
Class EmailReporter {
}
I have
package com.parent.spring;
public abstract class ParentConfig {
#Bean
public String bParent() {
return "parent bean";
}
then
package com.child.spring;
public class ChildConfig extends ParentConfig {
#Bean
public String bChild() {
return "child bean";
}
}
and here's how I am starting my spring boot app
#SpringBootApplication
#ComponentScan(basePackages = { "com.child.spring","com.parent.spring" })
public class MyMain {
public static void main(String args[]) throws Exception {
SpringApplication.run(MyMain.class, args);
}
}
I want to load beans from child config first and the from parent config. However, opposite is happening. Don't want to use depends on option as this is just an example, in reality I have lot of beans in child and parent config. Also, I have bunch of other configuration classes in parent package so I don't want to remove that from component scan. Any nicer solution on this ?
I want to load beans from child config first and the from parent
config.
You want to explain to the framework how to do its work ?
Spring Configurations and more generally Spring beans are loaded and added in the context in a order that Spring considers the right to satisfy all dependencies requirements.
Besides, configuration inheritance is not documented as a way to achieve such a thing.
Specifying explicitly the order for specific beans is possible but it should be the exception and not the norm while you seem want to do that exception the norm.
Could you please explain more your use case so that we could provide you the best solution we can :) ?
In general its a wrong approach to treat #Configuration files as regular java classes and use all the power of java as a language for the code in this files. You mention inheritance, how about complicated if-conditions, loops, recursion, anyone? :) My point is that you don't really want to end up with complicated code in configuration and to debug it.
Now regarding the inheritance itself. This is not a good idea, because given the fact that its not a regular java class combined with the understanding of how exactly spring uses these configuration files, you'll understand that configuration gives nothing to you here.
Think about configurations as a place where you state which beans should be loaded. Spring will take care of the rest. I do understand that you have some use case in mind, but it simply doesn't fit Spring approach.
As for your statement:
I want to load beans from child config first and the from parent config.
Could you please explain why do you need this?
When spring loads it scans all the configurations first but doesn't create beans (not yet). Instead it "translates" the information found in these #Configuration classes to a "metadata" (this is called "Bean Definitions" in terms of spring). All the bean definitions from all the configurations....
Only after that Spring starts beans instantiation (it also knows by this time what bean should be created first, for example if you have something like):
class A {
private B b;
public A(B b) {this.b = b;}
}
class B {
....
}
Then its obvious that Spring should create Bean "B" first.
I've found Sling's ability to associate Servlets with certain resource types, selectors and extentions, methods really useful in component development.
Now I'm starting to look into the ComponentFilterChain & would like to create filters that only register against certain resource types, in the same way as Servlets above.
From the Example filters on the Sling project, I see that there's a pattern property that you can apply for particular paths, though it feels like this limits the benefit of having components.
Really what I'm looking for is an equivalent property to sling.servlet.resourceType that I can annotate my Filter with so that only certain components enter this filter as part of the component filter chain, rather than having to check the component resourceType/superResourceType within the Filter.
Is this possible with Sling filters? Or is there an equivalent approach that can be used?
Out of the box, there's no way to associate servlet Filters with Sling resource types. Composing OSGi services, maybe using sling:resourceType values set as service properties, should allow you to provide similar functionality.
As of Apache Sling 2.6.14, there is an option to associate Sling Filters with resource types.
The property you need to add to your OSGi service to achieve this is sling.filter.resourceTypes.
There's a set of annotations available that make the job easier.
From the Sling Documentation
//...
import org.apache.sling.servlets.annotations.SlingServletFilter;
import org.apache.sling.servlets.annotations.SlingServletFilterScope;
import org.osgi.service.component.annotations.Component;
#Component
#SlingServletFilter(scope = {SlingServletFilterScope.REQUEST},
suffix_pattern = "/suffix/foo",
resourceTypes = {"foo/bar"},
pattern = "/content/.*",
extensions = {"txt","json"},
selectors = {"foo","bar"},
methods = {"GET","HEAD"})
public class FooBarFilter implements Filter {
// ... implementation
}
Let's imagine we have such a component in Spring:
#Component
public class MyComponent {
#Value("${someProperty}")
private String text;
}
If we define the property placeholder:
<context:property-placeholder location="classpath:myProps.properties"/>
And myPropos.properties contains the value for someProperty the value will be injected to the text field when the context is initialized. That's quite simple and easy.
But let's say that I have a service that enables user to change the value of the someProperty:
public void changeProp(String name, String newValue);
Is there a chance I can re-inject the newValue to text field. I mean it should be quite straight forward.. Basically it's nothing different than the after-initialization injection. I can not imagine that Spring does not have support for this? Can I fire some event or something?
I could do this on my own basically, but I wander is it maybe something there already? If not does anyone know what Spring class is in fact handling the injections at the first place? I could probably reuse the code there do perform this on my own if a solution does not exists.
I expect spring does not have a support for this, because the normal injection is done while creating the bean, but not will it is put in service.
Anyway: in this blog entry "Reloadable Application Properties with Spring 3.1, Java 7 and Google Guava", you can find the idea for an solution.
The key idea is to use a post processor to build a list of all fields with property fields. And if the properties are changed on can use this list to update the fields.