Spring: change i18n file location and resource loading issue - java

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

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?

SpringBoot: java.io.FileNotFoundException: file [] cannot be resolved in the file system for checking its content length

I'm trying to return an image from a springboot controller as the Resource object but I'm getting the error java.io.FileNotFoundException: file [/home/user/eclipse-workspace/MedVibes-1/ironman.png] cannot be resolved in the file system for checking its content length
Controller
#RestController
public class MedVibesController {
#Autowired
ResourceLoader resourceLoader;
#RequestMapping(value = "/file", method = RequestMethod.GET)
#ResponseBody
Resource resource = new FileSystemResource("ironman.png");
return resource;
}
I've an ironman.png file in both the MedVibes-1 directory as well as it's static folder
Still I'm getting the FileNOtFoundException? What's wrong with my code?How to fix this error?
FileSystemResource looks for the file in the FileSystem. if you want to use this, you have to specify full path.
You can use ClassPathResource
Resource resource = new ClassPathResource("static/ironman.png");
By default, it will look into resources folder.
Another way
#Autowired
ResourceLoader resourceLoader;
Resource resource = resourceLoader.getResource("classpath:ironman.png");
add the path:
Resource resource = new FileSystemResource("/static/ironman.png");
or
Resource resource = new FileSystemResource("/ironman.png");
depends on wich of the both files you want

Spring boot jar not reading/parsing application.properties root folder

Situation
I have a fat .jar of a Spring boot application. I've externalized my configuration with an application.properties file. This file is in the same folder as the .jar, and I'm starting the .jar from the command line from within the same folder (with the command "java -jar $jarFileName").
Then an exception is thrown:
nested exception is org.springframework.beans.TypeMismatchException:
Failed to convert value of type 'java.lang.String' to required type 'int'; nested exception is
java.lang.NumberFormatException: For input string: "${elasticsearch.port}"
As you can see, instead of reading the value from the properties file, it just sets the string as the text in the #Value annotation, which looks like this:
#Value("${elasticsearch.port}")
private int elkPort;
The class this happens in is annotated with #Component.
According to Spring docs: externalized configuration, spring should read an application.properties file outside of the jar.
When the same application.properties file is placed in src/main/resources it works fine, so the configuration file seems correct.
Any ideas why it won't load the external configuration file?
EDIT 1
I've also tried running it with --spring.config.location=file:application.properties and --spring.config.location=file:/full/path/to/application.properties but with the same result as above.
EDIT 2: classpath attempt
Also tried classpath instead of file, the same as the commands above but file replaced with classpath.
Lastly tried without either, so just --spring.config.location=/path/to/file; again both with relative and full path to the application.properties. All attempts gave the same result/exception.
EDIT 3
My annotated application:
#SpringBootApplication
public class ApplicationName {
public static void main(String[] args) {
SpringApplication.run(ApplicationName.class, args);
}
}
EDIT 4
Tried adding a PropertySourcesPlaceholderConfigurer as follows:
#Configuration
public class PropertyConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
And then for each #Value I added a default value; it still only resolves to the default values instead of to the application.properties values.
Alright after quite some struggles, I've found the solution. I was close with PropertySourcesPlaceholderConfigurer but not quite there yet; this is the full class now:
#Configuration
public class PropertyConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
final PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
ppc.setIgnoreResourceNotFound(true);
final List<Resource> resources = new ArrayList<>();
resources.add(new FileSystemResource("relative/path/to/application.properties"));
ppc.setLocations(resources.toArray(new Resource[]{}));
return ppc;
}
}
EDIT
To demonstrate the issue, I've created a repository to show the problem, see here: https://github.com/Locitao/test-external-properties
As it says on mentioned page, you should specify external config location
$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
Try without file keyword
--spring.config.location=/full/path/application.properties
I just took my application.properties out of an Eclipse Spring Boot project and it failed.
Then I put the file in a cfg folder in the root of the project and added program argument:
--spring.config.location=cfg/application.properties
and it worked again. Mayby if you try a relative path (no leading /) to the file (without the "file:") it will work.

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

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";
}

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?

Categories

Resources