Spring: Injecting Resource as InputStream into a factory-method - java

I want to use anti-samy from OWASP.
They got a Policy object, that is instantiated via a factory method.
public static Policy getInstance(InputStream inputStream);
The InputStream that needs to be passed to the factory-method represents the config file for the policy-object.
Is it possible to use create a policy bean in an spring xml context config?
I know, that there is a Resource object, that can load files from classpath. But what I need is to make a InputStream out of that Resource object. Can I doe this directly in the xml-spring-context? Or do I need to write java code in order to get the InputStream?

Use the factory-method approach together with a constructor-arg (that will be mapped to a factory method argument) and automatically converted to an InputStream from a resource notation.
<bean id="policy" class="org.owasp.validator.html.Policy"
factory-method="getInstance">
<!-- type needed because there is also a getInstance(String) method -->
<constructor-arg
value="classpath:path/to/policyFile.xml"
type="java.io.InputStream" />
</bean>
See the following parts of the Spring Reference:
Instantiation with a static factory
method
Built-in Property Editors (InputStreamEditor is relevant here)
Examples of Dependency Injection (last section is about constructor-arg used in the context of a static factory-method)

#seanizer's solution would be a good one if Policy closed the InputStream after it was finished reading from it, but apparently it doesn't. This will result in a leak, the severity of which depends how often it is called, and the nature of the resource.
To be safe, you should consider writing a custom FactoryBean implementation instead, which handles the opening and closing of the InputStream safely. The FactoryBean would be injected with a Resource object.

Related

Enforce initialization of Spring Bean which's reference is not explicitly used

Is there a way to enforce the initialization of a Spring Bean in cases that the reference of the bean is never explicitly used or even requested in the ApplicationContext?
<bean class="foo.bar.FooBar>
<property name="fooBar" ref="foo.bar.reference"/>
</bean>
This bean is meant to do things inside, get's properties passed by IoC but it is never used by any other bean which implies that the it's reference is nowhere else configured.
My problem is, that this bean seems not to be initialized because of that.
I tried <bean .. lazy-init="false"/> but this did not do the trick.
How can ensure the bean is going to be initialized?
Since I cannot modify the application context, I would need a way doing it just in the XML configuration.
I'm not sure, but maybe you could try to use the singleton=true property for that bean - in non-singleton mode, the bean would be instatiated only if requested by the application.
http://docs.spring.io/spring/docs/1.2.9/reference/beans.html
(see 3.2.5)
Edit: Can you add some logging to ctor to see if it's called? If not, could you add an init-method and log something there?

Spring java.lang.LinkageError: loader constraint violation: loader previously initiated loading for a different type with name X

I am new to Spring and use Spring 3.2.2. I have some beans which I injected via <constructor-arg> which works fine. Now I wanted to inject some bean via #Autowired which totally went wrong. I have done this:
beans.xml:
<context:annotation-config />
<bean id="formulaFactory" class="my.project.formula.impl.GenericFormulaFactory"
factory-method="getInstance">
<qualifier value="formulaFactory"></qualifier>
</bean>
Java source:
#Autowired
#Qualifier("formulaFactory")
private FormulaFactory formulaFactory;
(Changing the qualifier or leaving it out did not make any difference...)
And I get this error:
java.lang.LinkageError: loader constraint violation: loader (instance of org/springframework/context/support/ContextTypeMatchClassLoader$ContextOverridingClassLoader) previously initiated loading for a different type with name "my/project/formula/FormulaKey"
I wonder why this error comes up. Especially the type FormulaKey irritates me. When I use the #Autowired annotation with some other bean, it works.
I have to mention that I implemented the GenericFormulaFactory as singleton via getInstance method. Maybe that causes some problems?
The application is a stand-alone app. I checked all the jars for duplicity too and I do not assume that this is the cause of the problem because the error relates to my own classes.
Regards,
Oliver
UPDATE:
I removed the error without knowing what cause it.
What I did:
Remove the getInstance() method and singleton nature of the factory implementation
Added the factory interface to a handler classes constructor (and constructor-arg in xml)
Now I can use the xml to configure the implementation and use it with #Autowired annotations too.
xml:
<bean id="formulaHandler" class="my.project.formula.impl.DefaultFormulaHandler">
<constructor-arg ref="formulaFactory" />
</bean>
<bean id="formulaFactory" class="my.project.formula.impl.GenericFormulaFactory" />
Still wondering why the error came up in the first place. In the implementation of the factory, a HashMap was created using FormulaKey as key, so maybe this caused trouble. If someone knows the answer, I would really like to know it.
Here is what I could gather so far:
The error java.lang.LinkageError comes in a situation when there are two classloaders involved in loading a class.
A classloader keeps track of the classes loaded by generating a unique identifier which contains the fully qualified class name itself and the classloader which loaded it.
When a classloader receives a reference of a class loaded by another class which is already loaded by itself, this results into erroneous situation, as a class can be loaded only once, in a classloading hierarchy.
When custom classloaders are involved, for loading a particular class, the practice is that the parent classloaders are queried first if that class is already loaded.
In the scenario, when a custom classloader does not query the parent hierarchy and decided to load the class itself, there might be case wherein the class being loaded is already loaded by some classloader in parent hierarchy.
Read Kieviet, Frank's "The java.lang.LinkageError: loader constraint violation" demystified" to know more about it.
For your case, I guess the XML configuration and Annotation processing is done by two different classloaders.
In the error scenario, my.project.formula.FormulaKey is loaded by one classloader and then the class loader involved in annotation processing loads it one more time.
When you changed the code, the loading of my.project.formula.FormulaKey is deferred as its no more referred while loading the context from XML .

Spring prototypes inherit properties at runtime

What is the best approach for creating services that load a property set at runtime (bean is passed "xyz" and loads xyz.properties)? These properties files need to be able to be dropped into a folder outside the classpath before a command is entered to start the service (edit: this could happen at any time while the program is running).
I already have a system to do this that we've been using for over a year, but I'm migrating to spring to make the code more modular (customize services more easily through DI) and easier to maintain. My current method of creating an environment and then passing it with "this" to the dependencies just seems upside down from an IoC standpoint.
Is there a way to use a PropertyPlaceholderConfigurer without hardcoding the name of the property file? Maybe just a reference to a variable I pass into the constructor of the service that its dependencies can load? So far, it looks like I will have to create a service and inject its dependencies without any config and then call a separate load method for each to pass in the properties, but that just seems like I'm not really using spring.
USE CASE: The app will pool client connections to various servers and will forward requests from other applications to these servers. New profiles must be able to be added by non-programmers without taking down or restarting the app. The profiles will include basic things like host, port, and login info, but also more complex things like whether to use tcp/http, ssl/https (which will determine which client type to use), and timeouts and pool min/max/etc (which will need default values).
I tried with PropertyPlaceholderConfigurer and frankly, I couldn't wrap my head around it, somehow. It's easy enough to use when you use the existing options but I couldn't extend the framework.
So my approach was much more simple:
Create an annotation #InjectConfig which takes a config key as parameter.
In your beans/services, annotate fields or public setters with this annotation.
Write a BeanPostProcessor which takes options from a "config provider" and injects them into the fields / setters.
Now all you need is a config provider. Inject that into the post processor and you're done.
Note: I prefer annotating setters because that means you can easily configure your services from tests (just call the setters) without having to come up with smart names for 238576 config files.
EDIT If you have many configs, then a config factory might be a better choice:
Create a key to describe a config bundle (I usually use an enum or a new type here to prevent typos)
Put this key into the service when you create it (manually or via Spring)
Write a config factory that can return Properties or a Map for a config key.
Inject this factory into your service
In the init code of your service, use the key to lookup your config via the factory.
Using this approach, you can have a dummy factory that always returns the same thing in tests and a more complex factory for production.
The real factory can then be configured via spring so it knows where to look for configuration files. One approach is to register a java.io.File per config key. Now your concerns (configuring a service and loading configs) are completely separated.
PropertyPlaceholderConfigurer reads and initialize files on application context initialization and only once. So most probably you cannot configure it at runtime.
But you can have variables. For example, for my case I have default properties and user specific properties. So PropertyPlaceholderConfigurer loads properties from classpath first and after that is trying to find additional properties at defined location (user home folder). I user's property file exists so configurer loads it and override properties.
Here is my example:
<bean id="config" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true"/> <!-- do not throw exception if file not found -->
<property name="locations">
<list>
<value>classpath:server.properties</value>
<value>file:${user.home}/user.properties</value>
</list>
</property>
</bean>
I'm not sure that this answer is what you're exactly need. But I'm trying to guess what is your actual task. So if you need re-read properties runtime each time you access them you have to do it manually like you did before because spring application context helps you configure your application initial configuration.
It seems like the best approach may be to use a ServiceManager that contains the main ApplicationContext and then have each Service initialize its own FileSystemXmlApplicationContext with the main context as the parent like so:
public class ServiceManager {
ApplicationContext appContext;
String APP_HOME = System.getProperty("user.home") + File.separator;
public void init() {
//set main spring context
appContext = new AnnotationConfigApplicationContext(AppConfig.class);
}
public void start(String serviceName) throws Exception {
ApplicationContext serviceContext = new FileSystemXmlApplicationContext(
new String[]{APP_HOME + serviceName + ".xml"}, //path to child ctx
appContext); //reference to parent ctx to build hierarchy
Service service = (Service) serviceContext.getBean("service");
service.start();
}
}
The ApplicationContext is a bit heavy to be duplicating, but memory is pretty cheap these days and this provides total separation of concerns. I still have shared logging and an event system managed by the parent context, and each service is now simplified in its own config. I built a proof of concept using two services, and it seems to work fine so far. I'll add another comment once I finish the other services and finish testing.
reference:
http://techo-ecco.com/blog/spring-application-context-hierarchy-and-contextsingletonbeanfactorylocator/

spring mvc exception handler with #RequestBody

In my Spring MVC application I have a number of methods that use #RequestBody to bind to domain objects I've defined (specifically, from JSON using Jackson).
I'm currently using a simple view for exceptions as follows:
<bean id="exceptionHandler" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="defaultErrorView" value="errorXmlView" />
</bean>
<bean id="errorXmlView" class="com.example.MyCustomXmlView" />
My question is, inside MyCustomXmlView, which currently just extends AbstractView, is there a way I can get access to the object that was bound with #RequestBody? Assuming, that is, that it got that far and it wasn't a binding exception. For example, is there some kind of request-scoped bean I could call upon, or a way to get the object injected into the model for my exception view? If not, is there a different way of defining an exception resolver that would allow me to do that?
Have you considered the #ExceptionHandler annotation? The spring documentation has an example of its usage, and I imagine you can create a custom exception that will hold onto your model, which you should then be able to access in your exception handling method.
I often times capture controller method parameters with a ThreadLocal, and then store them for later use in logging, etc. The best way I've found is to use an #Aspect (or whatever AOP strategy you prefer) to intercept the controller methods and store the method parameters for later use.

Spring set abstract bean property value

I need to chance spring bean property values on runtime. Currently I'm doing it this way
Object bean = context.getBean(beanName);
BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(bean);
wrapper.setPropertyValue(propertyName, newValue);
But some beans are configured as abstract
<bean id="abstractFoo" abstract="true" class="com.Foo" />
<bean id="bar" class="com.Bar">
<constructor-arg><bean parent="abstractFoo" /></constructor-arg>
</bean>
and in that case context.getBean("abstractFoo") throws BeanIsAbstractException
This is really simplified example, but I hope you get the idea.
Any idea how to change property value of abstract bean (in this case 'abstractFoo')?
We're using spring 2.5.4
Edit
Changed a XML example to be more specific. abstractFoo is declared abstract because of security reasons.
Spring application context contains bean definitions, and Spring instantiates bean objects defined by these definitions.
Your current code obtains an object that was created from the named bean definition, and changes its property. However, abstract beans are never instantiated as objects, they exist only in the form of definitions which are inherited by definitions of concrete beans.
So, if you want to change properties of abstract beans, you need to change their definitions, that can be done using BeanFactoryPostProcessor. Note, however, that post-processors are applied during container startup, so if you want it to be actually "runtime", you this approach is not applicable.
Disclaimer: this is untested; off the top of my head. Not sure if it will work after the init phase.
You need to get in instance of a ConfigurableListableBeanFactory. Your appcontext probably is one, so you can probably cast it.
From there, get the bean definition and change the property.
ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory)context;
BeanDefinition fooDefinition = clbf.getBeanDefinition("abstractFoo");
MutablePropertyValues pv = fooDefinition.getPropertyValues();
pv.add(propertyName, newValue);
Maybe you need to re-register your beandefinition with the ConfigurableListableBeanFactory after that. I'm not 100% sure; you'll have to test that.
Keep in mind that if it works, it will only work for beans that are instantiated after the change.

Categories