Spring: How to access contents of webapp/resources in service layer - java

How do I access the contents of my webapp/resources folder from the service layer? I need to access a JSON file to be used for Elasticsearch mappings...
This is how my project structure looks like:
https://www.dropbox.com/s/crdzae1ko0x9p89/Screenshot%202015-05-25%2010.24.12.png?dl=0
I tried this:
http://www.mkyong.com/java/java-read-a-file-from-resources-folder/
String mapping = String.format("es_mappings/%s.json", type);
ClassLoader classLoader = getClass().getClassLoader();
String result = IOUtils.toString(classLoader.getResourceAsStream(mapping));
But I got a null pointer exception for the third line in the code snippet above.
Also tried this:
File file = ResourceUtils.getFile("classpath:es_mappings/bom_exports.json")
String txt= FileUtils.readFileToString(file);
But I got this error: java.io.FileNotFoundException: class path resource [es_mappings/bom_exports.json] cannot be resolved to absolute file path because it does not reside in the file system.
I have this in my -servlet.xml file:
<mvc:resources location="/resources/" mapping="/resources/**"/>
Thanks.

I using this code. It's simple and works.
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
// ...
#Value("/resources/json/your_file.json")
private Resource jsonResource;
// ...
InputStream jsonStream = jsonResource.getInputStream();
Now you can use stream to read json.

Using relative paths depends on the classloader, so you need to either work out where your classloader is looking or else just use an absolute path -
when using getResourceAsStream you need to start with a leading / so try this:
String mapping = String.format("/es_mappings/%s.json", type);
ClassLoader classLoader = getClass().getClassLoader();
String result = IOUtils.toString(classLoader.getResourceAsStream(mapping));
Also I'm not sure the webapp/resources folder will be added to the classpath by default in maven. Usually resources like files you need to access at runtime would be in the src/main/resources directory. (but I could be wrong, the easy way to tell is check the packaged war file, if the files are in /WEB-INF/classes then they are on the classpath)

ResourceUtils.getFile("classpath:es_mappings/bom_exports.json")
This method get resources file from the webapp/WEB-INF/classes when you pass classpath:*.
If you want get the json file from webapp/resources/es_mappings/your_file.json, the service class can implement the interface ServletContextAware and get servletContext. Because the webapp directory is determined by the web container such as tomcat or jetty, it only get the relative path from servletContext.getResource(). That method can get resources under webapp.
Code example maybe like:
class your_service implements ServletContextAware {
private ServletContext servletContext;
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
public void getJsonResource() {
...//other code
String josnFilepath = servletContext.getResource(
"/resources/es_mappings/your_file.json");
}
}
Also you can get the webapp directory by finding "WEB-INF/classes" substring in classpath.
String path = this.getClass().getResource("").getPath();
String fullPath = URLDecoder.decode(path, "utf-8");
String pathArr[] = fullPath.split("/WEB-INF/classes/");
if (2 == pathArr.length) { //pathArr[0] is webapp directory path
String jsonFilepath = pathArr[0] + "/resources/es_mappings/your_file.json";
}

Related

How to ensure Spring `Resource::createRelative` returns relative file resource for directory resource without trailing slash?

Hej,
in a Spring Boot application I need to use a base directory on the filesystem and access file resources relative to that.
Spring Boot allows to configure a directory via application.properties and a file:// URL as value.
When the property is missing its trailing slash, Resource::createRelative() fails to actually return a relative resource.
What kind of code or configuration do I need to make the createRelative() call work as intended, e.g. by ensuring that the Resource ends with a trailing slash?
The follwing test should illustrate my use case / problem:
#SpringBootTest
// NOTE: directory is missing trailing slash
#TestPropertySource(properties = "demo.directory=file://C:/Windows")
class RelativeFileUrlResourceTest {
#ConfigurationProperties(prefix = "demo")
static class TestProperties {
Resource directory;
public Resource getDirectory() {
return directory;
}
public void setDirectory(Resource directory) {
this.directory = directory;
}
}
#TestConfiguration
#EnableConfigurationProperties(TestProperties.class)
static class Config {
}
#Autowired
TestProperties testProperties;
#Test
void givenCreateRelative_thenResourceShouldBeRelative() throws IOException {
Resource directoryResource = testProperties.getDirectory();
File directoryFile = directoryResource.getFile();
assertTrue(directoryFile.isDirectory());
Resource relativeResource = directoryResource.createRelative("relative");
File relativeFile = relativeResource.getFile();
assertEquals(directoryFile, relativeFile.getParentFile());
}
}
The test fails with:
org.opentest4j.AssertionFailedError:
Expected :C:\Windows
Actual :C:\
The magic C:/Windows value is just an example of a folder that exists and does not have a trailing slash for test purposes. Once the trailing slash is added, i.e. C:/Windows/, the test passes.
Further note that both the canonical and absolute directory File do not contain a trailing slash either (at least tested on Windows).
The relative (file) resource is needed to pass it up all the way to a Spring MVC controller while using the Spring Resource abstraction to access it as a generic InputStream.
The actual application contains some logic to determine the relative file from the HTTP request instead of a hardcoded "relative" filename.
Is Resource::createRelative() unfit for this kind of use case? What other abstractions / solutions does Spring (Boot) offer?

Spring: change i18n file location and resource loading issue

I'm trying to override the i18n file location at runtime using a property that contains its full (absolute) path.
This is what I have:
#Bean
public MessageSource messageSource(#Value("${fileLocation}") String fileLocation) {
ReloadableResourceBundleMessageSource source = new ReloadableResourceBundleMessageSource();
source.setBasenames("file:" + fileLocation, "classpath:i18n/message");
return source;
}
However the resource isn't loaded.
At org.springframework.context.support.ReloadableResourceBundleMessageSource::refreshProperties, there is the following line:
Resource resource = this.resourceLoader.getResource(filename + PROPERTIES_SUFFIX);
and resourceLoader is a XmlWebApplicationContext.
I've also tried prefixing my absolute file path with file://, but it isn't loaded either.
What am I doing wrong ? How to load a file from its absolute path with the XmlWebApplicationContext ?
Note: I've read this documentation on how to load resources with Spring but what I get from it is that it should work if I prefix my resource with file:, however it doesn't work.
Thanks

Spring MVC file not found exception

I'm using Spring MVC. In my controller I called a function from MyClass
MyClass{
public static void readFile(){
File file = new FileReader("myPath/myFile.txt");
...
}
public static void main(String[] args) {
readFile();//No problem
}
}
controller:
#Controller
public class MyController{
#RequestMapping(value = "/url", method = RequestMethod.GET)
public String readFile(Locale locale, Model model) {
MyClass.readFile();//File not found exception
....
}
}
The reading works when I test it in the main() of MyClass, but when I run the project on server and visit "/url", I got this:
java.io.FileNotFoundException: myPath/myFile.txt (The system cannot find the path specified)
How do I specify the path in the controller?
Thank you for your time.
What is the working directory on the server? From that directory, does the relative path to the file ("myPath/myFile.txt") exist on the server?
Assuming you only need to read myFile.txt, then typically myFile.txt would be included within the WAR, and read via getResourceAsStream.
I think you are looking for Resource implementations in Spring. Spring will determine which type of Resource to use, for example if your file is in the classpath Spring will create a ClasspathResource or it points to a file it will create a FileResource. If you are using Spring 4. Try something like
#Value("file:///myPath/myFile.txt")
Resource myFile;
Have a look at this Spring Resources docs
because this is not absolutely path. Program will find files under Working Directory
you can add this into first program and the second one
System.out.println("Working Directory = " +
System.getProperty("user.dir"));
You will see the difference.

Get fully qualified resource name in web application in Java

I would like to get access to files in resources folder my web app (independently from this is exploaded WAR or not). I have already used servletContext via Spring to getResource also FileSystem context.
In the end, I choose Spring ResourceLoader because seems that it's the most suitable approach in my case.
I don't like use #PropertySources annotation and get access to particular properties of *.properties files.
UPDATED
I deployed my app using Webspehere Liberty Profile.
#Component
public class FileCreator {
#Autowired
private ResourceLoader resourceLoader;
public String getRealPath(String location) {
String realPath = null;
try {
Resource resource = resourceLoader.getResource(location);
String resourceDesc = resource.getDescription();
realPath = resource.getURI().getPath();
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
return realPath;
}
}
I have common maven layout for my Gradle app. It means that myApp.properties file located in /WEB-INF/classes folder
String scheduledServicesRealPath1 = fileCreator.getRealPath("classpath:myApp.properties");
I want to get the absolute path for this file but I 'm getting just null.
Does it exist any approach which can access resources independently from Application server, way of presentation of app on server (exploaded or not) and independent from file system?

Import location in wsit-client.xml to file in another jar, using an URL string to locate a file on the classpath

Normally the wsit-client.xml has import statements like this:
<import location="foo.xml" namespace="http://foo.org/" />
I've found that their can be online one wsit-client.xml on the classpath/META-INF, but can I refer to an xml who's located into another jar in that wsit-client.xml? Something like :
<import location="classPathResource/WEB-INF/foo.xml" namespace="http://foo.org/" />
I would like to create a single wsit-client.xml who contains the imports for all my webservices but I want to separate the configuration for all the different webservices in to different projects.
I've fixed it by creating an URLStreamHandler in the wsit-client.xml I can now define location="myprotocol://foo.xml"
I've used spring's PathMatchingResourcePatternResolver to locate my xml file in another project/jar.
public class Handler extends URLStreamHandler {
#Override
protected URLConnection openConnection(URL u) throws IOException {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
final URL resourceUrl = resolver.getResource(u.getPath()).getURL();
if (resourceUrl == null) {
throw new IOException(String.format("File %s not found on the classpath", u.getFile()));
}
return resourceUrl.openConnection();
}
}
I'm not using the VM arguments to define the handler but I've implemented an URLStreamHandlerFActory like explained over here URL to load resources from the classpath in Java
More info about writing your own protocol handlers can be find on this site: http://java.sun.com/developer/onlineTraining/protocolhandlers/
I've still got 1 project who contains the single wsit-client.xml with references to all my web service configurations, but at least I've managed to separate the configuration for all the different services in different maven projects.

Categories

Resources