EAR classloader doesn't see ApplicationInsights.xml located in jar - java

I have the following problem: I try to deploy the Azure telemetry configuration in jar file that is located in the war file inside main ear. Unfortunately, during server startup some errors occur as ApplicationInsights.xml cannot be found. I debugged it and I found out that it cannot be read by com.microsoft.applicationinsights.internal.config.ConfigurationFileLocator.getConfigurationFile().
There is a structure of my module:
azure
|_ src
|_ main
|_ java
| |_ mypackage
| |_ MicrometerRegistryConfigurationListener.java
|_ resources
|_ ApplicationInsights.xml
There is MicrometerRegistryConfigurationListener.java:
#WebListener
public class MicrometerRegistryConfigurationListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
MeterRegistry azureMeterRegistry = new AzureMonitorMeterRegistry(new AzureMonitorConfig() {
#Override
public String get(String key) {
return null;
}
#Override
public Duration step() {
return Duration.ofSeconds(5);
}
}, Clock.SYSTEM);
new JvmThreadMetrics().bindTo(azureMeterRegistry);
new JvmMemoryMetrics().bindTo(azureMeterRegistry);
new JvmGcMetrics().bindTo(azureMeterRegistry);
servletContextEvent.getServletContext().setAttribute("AzureMonitorMeterRegistry", azureMeterRegistry);
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
And there is a structure of ear:
ear
|_ war
|_ WEB-INF/lib
|_ azure.jar
|_ ApplicationInsights.xml
Of course, azure.jar contains also classes, i.a. MicrometerRegistryConfigurationListener.
What is going on? Why ApplicationInsights.xml is not visible?

Cause jar is a file, it's not a folder. The loader tries to access a file system path, but it can not access a path in your JAR. So you could use the resource.getInputStream() method to retrieve it as a InputStream. You could get details from this doc:Java: Load file from classpath in Spring Boot.
Example code:
public class EnvResolver {
private ResourceLoader resourceLoader;
public EnvResolver(){
resourceLoader = new DefaultResourceLoader();
}
public List GetEnvConfig() throws IOException {
Yaml yaml = new Yaml();
Resource resource = resourceLoader.getResource("classpath:test-environment.yml");
System.out.println("FileName: " + resource.getFilename());
InputStream inputStream = resource.getInputStream();
Map<String, Map<String, String>> result = yaml.load(inputStream);
List<TestEnvVo> envList = new ArrayList<>();
for (String key : result.keySet()) {
TestEnvVo testEnvVo = new TestEnvVo();
testEnvVo.setEnvName(result.get(key).get("name"));
testEnvVo.setDomain(result.get(key).get("domain"));
envList.add(testEnvVo);
}
inputStream.close();
return envList;
}
}
After searching, I found another way to configure it, in your POM file add the resources configuration. You could have a try.
<resources>
<resource>
<directory>src/main/resource</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.tld</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
Hope this could help you.
UPDATE:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
public class Hello {
public static void main(String[] args) throws IOException {
InputStream resourceInputStream = null;
URL resourceURL = Hello.class.getClassLoader().getResource("resources/hello.json");
if(resourceURL == null) {
System.out.println("Get the InputStream of file in IDE");
resourceInputStream = new FileInputStream(Hello.class.getClassLoader().getResource("").getPath()+"../../src/main/resources/hello.json");
} else {
System.out.println("Get the InputStream of file from runnable jar");
resourceInputStream = Hello.class.getClassLoader().getResourceAsStream("resources/hello.json");
}
System.out.println();
StringBuilder builder = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(resourceInputStream));
String line = null;
while((line = br.readLine()) != null) {
builder.append(line+"\n");
}
br.close();
System.out.println(builder.toString());
}
}

Related

Read file from resources folder in Spring Boot

I'm using Spring Boot and json-schema-validator. I'm trying to read a file called jsonschema.json from the resources folder. I've tried a few different ways but I can't get it to work. This is my code.
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("jsonschema.json").getFile());
JsonNode mySchema = JsonLoader.fromFile(file);
This is the location of the file.
And here I can see the file in the classes folder.
But when I run the code I get the following error.
jsonSchemaValidator error: java.io.FileNotFoundException: /home/user/Dev/Java/Java%20Programs/SystemRoutines/target/classes/jsonschema.json (No such file or directory)
What is it I'm doing wrong in my code?
After spending a lot of time trying to resolve this issue, finally found a solution that works. The solution makes use of Spring's ResourceUtils.
Should work for json files as well.
Thanks for the well written page by Lokesh Gupta : Blog
package utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ResourceUtils;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.io.File;
public class Utils {
private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class.getName());
public static Properties fetchProperties(){
Properties properties = new Properties();
try {
File file = ResourceUtils.getFile("classpath:application.properties");
InputStream in = new FileInputStream(file);
properties.load(in);
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
return properties;
}
}
To answer a few concerns on the comments :
Pretty sure I had this running on Amazon EC2 using java -jar target/image-service-slave-1.0-SNAPSHOT.jar
Look at my github repo : https://github.com/johnsanthosh/image-service
to figure out the right way to run this from a JAR.
Very short answer: you are looking for the resource in the scope of a classloader's class instead of your target class. This should work:
File file = new File(getClass().getResource("jsonschema.json").getFile());
JsonNode mySchema = JsonLoader.fromFile(file);
Also, that might be helpful reading:
What is the difference between Class.getResource() and ClassLoader.getResource()?
Strange behavior of Class.getResource() and ClassLoader.getResource() in executable jar
Loading resources using getClass().getResource()
P.S. there is a case when a project compiled on one machine and after that launched on another or inside Docker. In such a scenario path to your resource folder would be invalid and you would need to get it in runtime:
ClassPathResource res = new ClassPathResource("jsonschema.json");
File file = new File(res.getPath());
JsonNode mySchema = JsonLoader.fromFile(file);
Update from 2020
On top of that if you want to read resource file as a String, for example in your tests, you can use these static utils methods:
public static String getResourceFileAsString(String fileName) {
InputStream is = getResourceFileAsInputStream(fileName);
if (is != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
return (String)reader.lines().collect(Collectors.joining(System.lineSeparator()));
} else {
throw new RuntimeException("resource not found");
}
}
public static InputStream getResourceFileAsInputStream(String fileName) {
ClassLoader classLoader = {CurrentClass}.class.getClassLoader();
return classLoader.getResourceAsStream(fileName);
}
Example of usage:
String soapXML = getResourceFileAsString("some_folder_in_resources/SOPA_request.xml");
if you have for example config folder under Resources folder
I tried this Class working perfectly hope be useful
File file = ResourceUtils.getFile("classpath:config/sample.txt")
//Read File Content
String content = new String(Files.readAllBytes(file.toPath()));
System.out.println(content);
Spent way too much time coming back to this page so just gonna leave this here:
File file = new ClassPathResource("data/data.json").getFile();
2021 The Best Way
Simplest way to read file is:
Resource resource = new ClassPathResource("jsonSchema.json");
FileInputStream file = new FileInputStream(resource.getFile());
See my answer here: https://stackoverflow.com/a/56854431/4453282
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
Use these 2 imports.
Declare
#Autowired
ResourceLoader resourceLoader;
Use this in some function
Resource resource=resourceLoader.getResource("classpath:preferences.json");
In your case, as you need the file you may use following
File file = resource.getFile()
Reference:http://frugalisminds.com/spring/load-file-classpath-spring-boot/
As already mentioned in previous answers don't use ResourceUtils it doesn't work after deployment of JAR, this will work in IDE as well as after deployment
Below is my working code.
List<sampleObject> list = new ArrayList<>();
File file = new ClassPathResource("json/test.json").getFile();
ObjectMapper objectMapper = new ObjectMapper();
sampleObject = Arrays.asList(objectMapper.readValue(file, sampleObject[].class));
Hope it helps one!
How to get resource reliably
To reliably get a file from the resources in Spring Boot application:
Find a way to pass abstract resource, for example, InputStream, URL instead of File
Use framework facilities to get the resource
Example: read file from resources
public class SpringBootResourcesApplication {
public static void main(String[] args) throws Exception {
ClassPathResource resource = new ClassPathResource("/hello", SpringBootResourcesApplication.class);
try (InputStream inputStream = resource.getInputStream()) {
String string = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
System.out.println(string);
}
}
}
ClassPathResource is Spring's implementation of Resource - the abstract way to load resource. It is instantiated using the ClassPathResource(String, Class<?>) constructor:
/hello is a path to the file
The leading slash loads file by absolute path in classpath
It is required because otherwise the path would be relative to the class
If you pass a ClassLoader instead of Class, the slash can be omitted
See also What is the difference between Class.getResource() and ClassLoader.getResource()?
The second argument is the Class to load the resource by
Prefer passing the Class instead of ClassLoader, because ClassLoader.getResource differs from Class.getResource in JPMS
Project structure:
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
└── main
├── java
│ └── com
│ └── caco3
│ └── springbootresources
│ └── SpringBootResourcesApplication.java
└── resources
├── application.properties
└── hello
The example above works from both IDE and jar
Deeper explanation
Prefer abstract resources instead of File
Examples of abstract resources are InputStream and URL
Avoid using File because it is not always possible to get it from a classpath resource
E.g. the following code works in IDE:
public class SpringBootResourcesApplication {
public static void main(String[] args) throws Exception {
ClassLoader classLoader = SpringBootResourcesApplication.class.getClassLoader();
File file = new File(classLoader.getResource("hello").getFile());
Files.readAllLines(file.toPath(), StandardCharsets.UTF_8)
.forEach(System.out::println);
}
}
but fails with:
java.nio.file.NoSuchFileException: file:/home/caco3/IdeaProjects/spring-boot-resources/target/spring-boot-resources-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/hello
at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92)
at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:116)
when Spring Boot jar run
If you use external library, and it asks you for a resource, try to find a way to pass it an InputStream or URL
For example the JsonLoader.fromFile from the question could be replaced with JsonLoader.fromURL method: it accepts URL
Use framework's facilities to get the resource:
Spring Framework enables access to classpath resources through ClassPathResource
You can use it:
Directly, as in the example of reading file from resources
Indirectly:
Using #Value:
#SpringBootApplication
public class SpringBootResourcesApplication implements ApplicationRunner {
#Value("classpath:/hello") // Do not use field injection
private Resource resource;
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootResourcesApplication.class, args);
}
#Override
public void run(ApplicationArguments args) throws Exception {
try (InputStream inputStream = resource.getInputStream()) {
String string = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
System.out.println(string);
}
}
}
Using ResourceLoader:
#SpringBootApplication
public class SpringBootResourcesApplication implements ApplicationRunner {
#Autowired // do not use field injection
private ResourceLoader resourceLoader;
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootResourcesApplication.class, args);
}
#Override
public void run(ApplicationArguments args) throws Exception {
Resource resource = resourceLoader.getResource("/hello");
try (InputStream inputStream = resource.getInputStream()) {
String string = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
System.out.println(string);
}
}
}
See also this answer
stuck in the same issue, this helps me
URL resource = getClass().getClassLoader().getResource("jsonschema.json");
JsonNode jsonNode = JsonLoader.fromURL(resource);
create json folder in resources as subfolder then add json file in folder then you can use this code :
import com.fasterxml.jackson.core.type.TypeReference;
InputStream is = TypeReference.class.getResourceAsStream("/json/fcmgoogletoken.json");
this works in Docker.
Here is my solution. May help someone;
It returns InputStream, but i assume you can read from it too.
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("jsonschema.json");
The simplest method to bring a resource from the classpath in the resources directory parsed into a String is the following one liner.
As a String(Using Spring Libraries):
String resource = StreamUtils.copyToString(
new ClassPathResource("resource.json").getInputStream(), defaultCharset());
This method uses the StreamUtils utility and streams the file as an input stream into a String in a concise compact way.
If you want the file as a byte array you can use basic Java File I/O libraries:
As a byte array(Using Java Libraries):
byte[] resource = Files.readAllBytes(Paths.get("/src/test/resources/resource.json"));
If you're using spring and jackson (most of the larger applications will), then use a simple oneliner:
JsonNode json = new ObjectMapper().readTree(new ClassPathResource("filename").getFile());
Here is a solution with ResourceUtils and Java 11 Files.readString which takes care of UTF-8 encoding and resource closing
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.springframework.util.FileCopyUtils.copyToByteArray;
import org.springframework.core.io.ClassPathResource;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public JsonNode getJsonData() throws IOException {
ClassPathResource classPathResource = new
ClassPathResource("assets/data.json");
byte[] byteArray =
copyToByteArray(classPathResource.getInputStream());
return new ObjectMapper() //
.readTree(new String(byteArray, UTF_8));
}
Or even simpler
Step 1 : Create your resource file lets say under /src/main/resources/data/test.data
Step 2 : Define the value in application.properties/yml
com.test.package.data=#{new org.springframework.core.io.ClassPathResource("/data/test.data").getFile().getAbsolutePath()}
Step 3 : Get the file in your code
#Value("${com.test.package.data}")
private String dataFile;
private void readResourceFile() {
Path path = Paths.get(dataFile);
List<String> allLines = Files.readAllLines(path);
}
Spring provides ResourceLoader which can be used to load files.
#Autowired
ResourceLoader resourceLoader;
// path could be anything under resources directory
File loadDirectory(String path){
Resource resource = resourceLoader.getResource("classpath:"+path);
try {
return resource.getFile();
} catch (IOException e) {
log.warn("Issue with loading path {} as file", path);
}
return null;
}
Referred to this link.
just to add my solution as another 2 cents together with all other answers. I am using the Spring DefaultResourceLoader to get a ResourceLoader. Then the Spring FileCopyUtils to get the content of the resource file to a string.
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UncheckedIOException;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.FileCopyUtils;
public class ResourceReader {
public static String readResourceFile(String path) {
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource(path);
return asString(resource);
}
private static String asString(Resource resource) {
try (Reader reader = new InputStreamReader(resource.getInputStream(), UTF_8)) {
return FileCopyUtils.copyToString(reader);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
For me, the bug had two fixes.
Xml file which was named as SAMPLE.XML which was causing even the below solution to fail when deployed to aws ec2. The fix was to rename it to new_sample.xml and apply the solution given below.
Solution approach
https://medium.com/#jonathan.henrique.smtp/reading-files-in-resource-path-from-jar-artifact-459ce00d2130
I was using Spring boot as jar and deployed to aws ec2
Java variant of the solution is as below :
package com.test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;
public class XmlReader {
private static Logger LOGGER = LoggerFactory.getLogger(XmlReader.class);
public static void main(String[] args) {
String fileLocation = "classpath:cbs_response.xml";
String reponseXML = null;
try (ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext()){
Resource resource = appContext.getResource(fileLocation);
if (resource.isReadable()) {
BufferedReader reader =
new BufferedReader(new InputStreamReader(resource.getInputStream()));
Stream<String> lines = reader.lines();
reponseXML = lines.collect(Collectors.joining("\n"));
}
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
}
}
}
If you are using maven resource filter in your proyect, you need to configure what kind of file is going to be loaded in pom.xml. If you don't, no matter what class you choose to load the resource, it won't be found.
pom.xml
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
<include>**/*.yml</include>
<include>**/*.yaml</include>
<include>**/*.json</include>
</includes>
</resource>
</resources>
Below works in both IDE and running it as a jar in the terminal,
import org.springframework.core.io.Resource;
#Value("classpath:jsonschema.json")
Resource schemaFile;
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4);
JsonSchema jsonSchema = factory.getSchema(schemaFile.getInputStream());
You need to sanitize the path and replace %20 with a space, or rename your directory. Then it should work.
FileNotFoundException: /home/user/Dev/Java/Java%20Programs/SystemRoutines/target/classes/jsonschema.json
i think the problem lies within the space in the folder-name where your project is placed.
/home/user/Dev/Java/Java%20Programs/SystemRoutines/target/classes/jsonschema.json
there is space between Java Programs.Renaming the folder name should make it work
Using Spring ResourceUtils.getFile() you don't have to take care absolute path :)
private String readDictionaryAsJson(String filename) throws IOException {
String fileContent;
try {
File file = ResourceUtils.getFile("classpath:" + filename);
Path path = file.toPath();
Stream<String> lines = Files.lines(path);
fileContent = lines.collect(Collectors.joining("\n"));
} catch (IOException ex) {
throw ex;
}
return new fileContent;
}
Try this:
In application.properties
app.jsonSchema=classpath:jsonschema.json
On your Properties pojo:
NOTE: You can use any prefered way of reading configs from application.properties.
#Configuration
#ConfigurationProperties(prefix = "app")
public class ConfigProperties {
private Resource jsonSchema;
// standard getters and setters
}
In your class, read the resource from the Properties Pojo:
//Read the Resource and get the Input Stream
try (InputStream inStream = configProperties.getJsonSchema().getInputStream()) {
//From here you can manipulate the Input Stream as desired....
//Map the Input Stream to a Map
ObjectMapper mapper = new ObjectMapper();
Map <String, Object> jsonMap = mapper.readValue(inStream, Map.class);
//Convert the Map to a JSON obj
JSONObject json = new JSONObject(jsonMap);
} catch (Exception e) {
e.printStackTrace();
}
Nowadays, in 2023, Java users should be able to read a classpath file more easily.
With a simple instruction such as new File("classpath:path-to-file").
I had same issue and because I just had to get file path to send to file input stream, I did this way.
String pfxCertificate ="src/main/resources/cert/filename.pfx";
String pfxPassword = "1234";
FileInputStream fileInputStream = new FileInputStream(pfxCertificate));

getting resources inside a built application

i want to get files inside a folder when my application is running, so i know that i need to get it as resouce, if i will get it as file, it wont work, so it what i did.
jaxbContext = JAXBContext.newInstance(Catalogo.class);
jaxbUnmarshaller = jaxbContext.createUnmarshaller();
InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream("catalogos/");
BufferedReader br = new BufferedReader(new InputStreamReader(resourceAsStream));
String line;
try {
while((line = br.readLine()) != null){
InputStream resourceAsStream1 = getClass().getClassLoader().getResourceAsStream("catalogos/"+line);
tempCat = (Catalogo) jaxbUnmarshaller.unmarshal(resourceAsStream1);
if(tempCat != null){
codigoCurso = String.valueOf(tempCat.getCourse().getId());
nomeDoCurso = dados.get(codigoCurso);
anoCatalogo = String.valueOf(tempCat.getAno());
if(nomeDoCurso == null){
dados.put(codigoCurso, tempCat.getCourse().getNome());
}
anos.add(anoCatalogo);
}
}
What i want to do is, get all files inside a folder (/catalogos/) and loop through and unmarshall each to an object so i will be able to access the property i need. So, when i run this with netbeans, works perfectly, but when i build and run the jar, i dont get the same result i've got using netbeans, i mean, the data is not where i expected.
The following example demonstrates how to get files from a directory in current runnable jar file and read these files contents.
Assume you have a NetBeans project with name "FolderTestApp". Do the following steps:
In your project root folder FolderTestApp\ create folder myFiles.
Copy your catalogos folder to the FolderTestApp\myFiles\
myFiles folder is necessary to preserve catalogos folder in your jar file structure when project jar is being generated. myFiles folder will disappear from jar file, but catalogos folder will remain.
If you don't do these steps, and place catalogos directly to the project folder (not as a child folder for myFiles), then your files from catalogos folder will be placed to the root of your jar file.
Add myFiles folder as a source folder in netbeans project properties.
Assume your property files contain the following contents:
file1.properties:
key11=value11
key12=value12
key13=value13
file2.properties:
key21=value21
key22=value22
key23=value23
Please note, that code below is not optimized. It is plain'n'dirty proof of concept to show, how to solve your task.
Add the following class to your project:
package folderapp;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.util.Properties;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class FolderTestApp {
public static void main(String[] args) throws URISyntaxException, IOException {
new FolderTestApp();
}
public FolderTestApp() throws URISyntaxException, IOException {
// determining the running jar file location
String jarFilePath = getClass().getProtectionDomain().
getCodeSource().getLocation().toURI().getPath();
// note, that the starting / is removed
// because zip entries won't start with this symbol
String zipEntryFolder = "catalogos/";
try (ZipInputStream zipInputStream
= new ZipInputStream(new FileInputStream(jarFilePath))) {
ZipEntry zipEntry = zipInputStream.getNextEntry();
while (zipEntry != null) {
System.out.println("processing: " + zipEntry.getName());
if (zipEntry.getName().startsWith(zipEntryFolder)) {
// directory "catalogos" will appear as a zip-entry
// and we're checking this condition
if (!zipEntry.isDirectory()) {
// adding symbol / because it is required for getResourceAsStream() call
printProperties("/" + zipEntry.getName());
}
}
zipEntry = zipInputStream.getNextEntry();
}
}
}
public void printProperties(String path) throws IOException {
try (InputStream is = getClass().getResourceAsStream(path)) {
InputStreamReader fr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(fr);
Properties properties = new Properties();
properties.load(br);
System.out.println("contents from: " + path + "\n");
Set<Object> keySet = properties.keySet();
for (Object key : keySet) {
System.out.println(key + " = " + properties.get(key));
}
System.out.println("---------------------------------------");
}
}
}
Set this class as the main class in your project settings (Run section).
And build your project via menu: Run - Build.
As your project has been built, open FolderTestApp/dist folder, where your generated jar is located and run this jar file:
That's it :)

Spring Resource Inside JAR/WAR

I created a really simple project to test reading a directory or file using getClass().getResource('...').getPath() from STS, Tomcat, and running the JAR/WAR file from the terminal with the embedded Tomcat.
Like I said, the project is simple, here's the code:
package org.example
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.CommandLineRunner
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
#SpringBootApplication
class ResourceDemoApplication implements CommandLineRunner {
static void main(String[] args) {
SpringApplication.run ResourceDemoApplication, args
}
#Override
void run(String... arg0) throws Exception {
retrieveDirectory()
}
void retrieveDirectory() {
/*new File(getClass().getResource('/private/folders').getPath()).eachDirRecurse() { dir ->
dir.eachFileMatch(~/.*.txt/) { file ->
println(file.getPath())
}
}*/
println new File(getClass().getResource('/private/folders/').getPath()).isDirectory()
}
}
When this code runs in STS or if I drop it in a running Tomcat instance, it prints true. When I run it as java -jar..., it returns false in the terminal. I have looked at countless examples and I still don't understand how to get this to work properly or as expected. I know that reading files from inside the JAR is different than having access to the file system, but I'm not sure how to get this to work regardless of how it's deployed.
Thank you in advance for the help!
After quite a bit of research and digging into the code, I ended up with this solution:
package org.example
import org.springframework.boot.CommandLineRunner
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.core.io.FileSystemResource
import org.springframework.core.io.support.PathMatchingResourcePatternResolver
#SpringBootApplication
class ResourceDemoApplication implements CommandLineRunner {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver()
static void main(String[] args) {
SpringApplication.run ResourceDemoApplication, args
}
#Override
void run(String... arg0) throws Exception {
retrieveDirectory()
}
void retrieveDirectory() {
List<FileSystemResource> files = resolver.findPathMatchingResources('private/folders/**/example.txt')
files.each { file ->
println file.getInputStream().text
}
}
}
With groovy you don't need to declare types etc... I am doing it for the sake of documentation here to show what's happening in the code. If you do this in Java you will need something like this to replace println file.getInputStream().text:
InputStream is
BufferedReader br
String fileContents
files.each { file ->
is = file.getInputStream()
br = new BufferedReader(new InputStreamReader(is))
String line
fileContents = ""
while((line = br.readLine()) != null) {
fileContents += line
}
println fileContents
println "************************"
br.close()
}

How to access text file in Maven Project using ClassPathResource in Java?

I am trying to access file "raw_sentences.txt" file using "ClassPathResource" in Maven java project. My file is located in the "\src\main\resources\com\thesis\work\raw_sentences.txt". I have tried many ways but it always returning with an error NullPointerExcepetion. I can access the file from
File testf = new File( obj.getClass().getResource( "raw_sentences.txt" ).toURI() );
But ClassPathResrouce is not working i don't know why, please help!
package com.thesis.work;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.core.io.ClassPathResource;
public class App
{
static final Logger logger = Logger.getLogger("MyLog");
public static void main( String[] args ) throws IOException, URISyntaxException
{
App obj = new App();
File testf = new File( obj.getClass().getResource( "raw_sentences.txt" ).toURI() );
logger.log(Level.INFO, "File: ", testf.getPath()); // Works!
logger.log(Level.INFO, "Load data...\n");
ClassPathResource resource = new ClassPathResource("raw_sentences.txt");
logger.log(Level.INFO, "File loaded : ", resource.getPath()); // not Working!
}
static void print(String nd){
System.out.println(nd);
}}
Exception in thread "main" java.io.FileNotFoundException: class path resource [raw_sentences.txt] cannot be opened because it does not exist
at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:157)
at com.thesis.work.App.main(App.java:24)
Try ClassPathResource resource = new ClassPathResource("com/thesis/work/raw_sentences.txt");
They both shall be right.
Suppose there is the java file com/a/b/App.java, and the resource directory is com/a/b/test.test.
Then,
both
ClassPathResource resource = new ClassPathResource("/com/a/b/test.dat");
and
ClassPathResource resource = new ClassPathResource("test.dat");
should be fine.
The deep reason is that, maven would copy the contents of resource to target/classes/.
Therefore, the test.dat is in the same directory with App.class, and test.dat or /com/a/b/test.dat both are right.
Here is the file structure in target:
target
|__
classes
└── a
└── b
|__
test.dat
App.class

Eclipse shows errors when i write information in xml file

I use the JDOM library. When I write information into an xml file, Eclipse shows errors. The system cannot find the path specified. I try to create the file in the "language" folder. How can I create the folder automatically when I write info into this file? I think the error is in this line:
FileWriter writer = new FileWriter("language/variants.xml");
Here is my code:
package test;
import java.io.FileWriter;
import java.util.LinkedList;
import org.jdom2.Attribute;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
class Test {
private LinkedList<String> variants = new LinkedList<String>();
public Test() {
}
public void write() {
Element variantsElement = new Element("variants");
Document myDocument = new Document(variantsElement);
int counter = variants.size();
for(int i = 0;i < counter;i++) {
Element variant = new Element("variant");
variant.setAttribute(new Attribute("name",variants.pop()));
variantsElement.addContent(variant);
}
try {
FileWriter writer = new FileWriter("language/variants.xml");
XMLOutputter outputter = new XMLOutputter();
outputter.setFormat(Format.getPrettyFormat());
outputter.output(myDocument,writer);
writer.close();
}
catch(java.io.IOException exception) {
exception.printStackTrace();
}
}
public LinkedList<String> getVariants() {
return variants;
}
}
public class MyApp {
public static void main(String[] args) {
Test choice = new Test();
choice.write();
}
}
Here is the error:
java.io.FileNotFoundException: language\variants.xml (The system cannot find the path specified)
at java.io.FileOutputStream.open(Native Method)
at java.io.FileOutputStream.<init>(FileOutputStream.java:212)
at java.io.FileOutputStream.<init>(FileOutputStream.java:104)
at java.io.FileWriter.<init>(FileWriter.java:63)
at test.Test.write(MyApp.java:31)
at test.MyApp.main(MyApp.java:49)`enter code here
As the name suggests FileWriter is for writing to file. You need to create the directory first if it doesnt already exist:
File theDir = new File("language");
if (!theDir.exists()) {
boolean result = theDir.mkdir();
// Use result...
}
FileWriter writer = ...
For creating directories you need to use mkdir() of File class.
Example:
File f = new File("/home/user/newFolder");
f.mkdir();
It returns a boolean: true if directory created and false if it failed.
mkdir() also throws Security Exception if security manager exists and it's checkWrite() method doesn't allow the named directory to be created.
PS: Before creating directory, you need to validate if this directory already exists or not by using exists() which also returns boolean.
Regards...
Mr.777

Categories