how to inject webapp resource using relative path in spring - spring

I have a bean which im trying to pass a relative path at web application startup. It works for an absolute path (running tomcat within eclipse) such as (C:/dev/workspace/project/src/main/webapp/WEB-INF/resource/)
However when I try to pass it a relative path such as WEB-INF/my_resource/ it says cannot find the location C:/dev/eclipse/WEB-INF/my_resource/ probably because tomcat is running within eclipse. How can I make this path relative so that it will be always picked up from whatever webcontainer is running it no matter the location of the webapp?
Ive read in place to use the servletconfig.getRelativePath(/) but neither know how to obtain the servlet config from within my bean or even if this is the right thing to do in Spring... Please help
The source code for my bean class and bean configuration xml can be found below
public class SuggestionIndexSearcher extends IndexSearcher {
private String indexSearcherType;
public SuggestionIndexSearcher(String type, String path){
super(path);
this.indexSearcherType = type;
}
...
}
The bean is defined in teh beans xml as...
<bean id="KMSearcherBean" class="com.hp.it.km.search.web.suggestion.SuggestionIndexSearcher">
<constructor-arg index="0" value="KMSearcher" />
<constructor-arg index="1" value="WEB-INF/resource/keyword" />
</bean>

If your change your bean to take org.springframework.core.io.Resource (javadoc) instead of String, then Spring will automagically coerce your path into the appropriate type of Resource. When running inside a servlet container, Spring will generally pick ServletContextResource, in which the path becomes relative to the webapp root (so WEB-INF/my_resource/ should work as you expect).
How your code chooses to handle Resource depends what you want to do with it, obviously.
No change is required in your XML config, just keep passing the path string as before. See the Spring manual for a wider description of resources.

Change the argument type from String to Resource - spring will then do the conversion and give you the resource object which you can process. You should be using an XMLWebApplicationContext (which is the default if the context is being created by the ContextLoaderListener or DispatcherServlet).
Take a look at this page for more details.

Related

Blueprint/Spring can't find 'classpath:path/to/file.ext' resource having moved project from Talend 6.5.1 to 7.1.1

In a Talend ESB (SE) project, I have a bean instantiated in the "Spring" configuration using a route resource.
In version 6.5.1 the following (used as a parameter) works fine.
<bean class="java.lang.String">
<constructor-arg>
<bean class="org.springframework.util.FileCopyUtils" factory-method="copyToByteArray" >
<constructor-arg value="classpath:query/sqlQuery.sql" type="java.io.InputStream" />
</bean>
</constructor-arg>
</bean>
but this doesn't for in my Talend 7.1.1 project. It seems to be unable to find the resource. I've looked in the created .kar file, and the resource is in the project .jar in the query folder.
[EDIT] It appears that Talend 7.1.1 encloses the "Spring" configuration in a <blueprint> element, which perhaps has change the way in which this functions.
I presume that something has changed in the way Talend packages the route, or in the way that the Spring xml is interpreted. Camel has no problem finding resources, for example from("sql:classpath:query/sqlQuery.sql"), but the "Spring" classpath search seems not to be able to find them.
I've tried substituting classpath*: for the straight classpath in the parameter as that had been suggested in some of the answers I'd seen to "resource not found" questions, but this didn't seem to be valid and was interpreted as a straight filename.
Am I doing something wrong with the classpath declaration? Is there another way of setting a spring/blueprint bean property with the contents of a resource file?
I've also tried explicitly declaring a ClassPathResource bean and it claims the resource does not exist when using the getInputStream() method, despite the fact I can see it if I open up the contained jar file.
Has the wrapping of the created feature in Maven terms (from Talend 7) had some impact on the classpath I need to use?

Spring Boot classpath: vs relative path

In Spring Boot, to access a resource, say myresource.json, I can use both classpath: or a relative path, like ./myresource.json
What is the difference? Which one should I use?
When you call getResource() on a specific application context, and the location path specified doesn't have a specific prefix like ./myresource.json, you will get back a Resource type that is appropriate to that particular application context.
If getResource() was executed against a ClassPathXmlApplicationContext instance it will return a ClassPathResource.If the same method was executed against a FileSystemXmlApplicationContext instance, you'd get back a FileSystemResource. For a WebApplicationContext, you'd get back a ServletContextResource, and so on.
As such, you can load resources in a fashion appropriate to the particular application context.
On the other hand, you may also force ClassPathResource to be used, regardless of the application context type, by specifying the special classpath: prefix.
See this doc

External path Properties file in spring mvc

1.spring-servlet.xml -
<context:property-placeholder location="local path of database properties file/database.properties"/>
if i put absolute path in above then i can access the file.
but my absolute path is in general.properties and
general.properties is in my class path
2.general.properties -
proPath=D:\\Propertiesfile
so how can i put database.properties file path in spring-servlet.xml
Thanks in advance.
You need to understand the Spring Resource abstraction. By default if a resource is not qualified with a handler prefix e.g classpath: file: etc Spring determines the type of resource to load based on the type of ApplicationContext used.
If its a ClassPathXmlApplicationContext it uses a classpath resource. If its a FileSystemXmlApplicationContext it uses a file system resource. If its a web application context it uses Servlet context resource. However you can force it to load a specific type irregardless of application context type by appending the handler prefix e.g classpath:database.properties which loads your file from the classpath
You can use <context:property-placeholder location="classpath:database.properties"/> if your database.properties is in the classpath
Or <context:property-placeholder location="database.properties"/> if your database.properties is in the root of the web application

Import resource based on JNDI in Spring 4.x

I want to import a resource based on a JNDI entry.
My application-context.xml looks like:
<jee:jndi-lookup id="td.naccms.cods2.config.path"
jndi-name="td.naccms.cods2.config.path" expected-type="java.lang.String"
default-value="classpath:application-context-persistence.xml" />
<context:property-placeholder />
<import resource="${td.naccms.cods2.config.path}" />
And tomcat returns the following error:
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from class path resource [application-context-cods2-web.xml]; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'td.naccms.cods2.config.path' in string value "${td.naccms.cods2.config.path}"
Note, I do not want to load the resources from a property files because the resourse to be imported is going to change based on the JNDI.
When using placeholders ${...} you can use a : to specify another value in case the expression doesn't resolve (this could even be another placeholder!).
So instead of hacking around with lookups yourself just pass the value using a :.
<import resource="${td.naccms.cods2.config.path:classpath:application-context-persistence.xml}" />
The Environment abstraction (used to do resolving of placeholders in newer Spring versions) also checks JNDI for the property next to the System Environment, Property files (loaded through #PropertySource) and in a web application the ServletContext.

how to handle name not found exception in application-context.xml?

I am creating a spring project using Oracle and jboss server.
I have one bean in my application-context.xml.
<!-- Datasource for TaskManager -->
<jee:jndi-lookup id="tmTestDataSource"
jndi-name="test_datasource" expectedtype="javax.sql.DataSource"/>
<bean id="tmTestJdbcTemplate" name="TmTestJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="tmTestDataSource" />
</bean>
If the 'test_datasource' JNDI (one datasource.xml file in jboss deployment folder, which contains db credentials like url, uid, password) inside the file found deployment is successfull, but if the file is not there then the deployment is failing.
I want to handle this exception so that deployment should not fail.
how I can do this. Can anybody provide me any solution.
Thanks.
Instead of using dataSource args constructor, you can set it using setter method.
This way your bean will be created but its datasource will be null. So you will get NPE if you try to use it, but at least bean creation tree will not be stalled.

Resources