I'm using JUnit 4, Java 8, and Gradle 1.12.
I have a file with default json that I need to load. My project has src/main/java/ (containing the project source), src/main/resources/ (empty), src/test/java/ (unit test source), and src/test/resources/ (the json data file to load) directories. The build.gradle file is in the root.
In my code I have:
public class UnitTests extends JerseyTest
{
#Test
public void test1() throws IOException
{
String json = UnitTests.readResource("/testData.json");
// Do stuff ...
}
// ...
private static String readResource(String resource) throws IOException
{
// I had these three lines combined, but separated them to find the null.
ClassLoader c = UnitTests.class.getClassLoader();
URL r = c.getSystemResource(resource); // This is returning null. ????
//URL r = c.getResource(resource); // This had the same issue.
String fileName = r.getFile();
try (BufferedReader reader = new BufferedReader(new FileReader(fileName)))
{
StringBuffer fileData = new StringBuffer();
char[] buf = new char[1024];
int readCount = 0;
while ((readCount = reader.read(buf)) != -1)
{
String readData = String.valueOf(buf, 0, readCount);
fileData.append(readData);
}
return fileData.toString();
}
}
}
From what I read, that should give me access to the resource file. However, I get a null pointer exception when I try to use the URL, because the getSystemResource() call returns null.
How do I access my resource files?
Resource names don't start with a slash, so you'll need to get rid of that. The resource should preferably be read with UnitTests.getClassLoader().getResourceAsStream("the/resource/name"), or, if a File is required, new File(UnitTests.getClassLoader().getResource("the/resource/name").toURI()).
On Java 8, you could try something like:
URI uri = UnitTests.class.getClassLoader().getResource("the/resource/name").toURI();
String string = new String(Files.readAllBytes(Paths.get(uri)), Charset.forName("utf-8"));
I think you want getResource instead of getSystemResource. The latter is used to, for example, read a file from the file system, where the path would not be specified in terms of the jar.
You can also skip the class loader: UnitTests.class.getResource("...")
Docs about resources here
Edit: there are some more detailed comments in the answers here.
Related
I try to open and read an HTML file from within class path.
Please find the directory structure in screenshot below
Inside class SendEmail class I want to read that verification.html file.
Code
When using the code below, it is throwing me a java.io.FileNotFoundException exception here:
emailContent = readHTMLFile("../emailTemplate/EmailVerificationTemplate/verification.html");
The readHTMLFile method looks like this:
public String readHTMLFile(String path) throws IOException {
String emailContent = "";
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new FileReader(path));
while ((emailContent = bufferedReader.readLine()) != null) {
stringBuilder.append(emailContent);
}
return stringBuilder.toString();
}
However, when I use an absolute path everything is working fine.
I am very new to Java world.
Please help me to fix this 🙏🏻.
verification.html looks rather like a "class path resource" than a file...
(A file is very environment dependent (e.g. thinking of its path/location), whereas a "CPR" we package & supply with our application & can refer to it with a known&fixed (absolute or relative) (class path) address.
Nor maven nor gradle (by default) "includes" anything else from src/main/java than *.java files. So please move the according files (including structure/packages) to src/main/resources (or src/test/... accordingly).
When the resource is finally in classpath, since spring:3.2.2, we can do that:
String emailBody = org.springframework.util.StreamUtils.
copyToString(
new org.springframework.core.io.ClassPathResource(
"/full/package/of/emailTemplate/EmailVerificationTemplate/verification.html")
.getInputStream(),
/* you must know(!), better: */
Charset.forName("UTF-8")
);
(..also outside/before spring-boot-application.)
In spring context, the Resource (Classpath-, ServletContext-, File(!)-, URL-, ...) can also be "injected", like:
#Value("classpath:/full/package/...")Resource verificationEmailBody
..instead of calling the constructor.
See also:
Spring Core#Resources reference doc
Resource javadoc
How do I read / convert an InputStream into a String in Java?
How do I load a resource and use its contents as a string in Spring
When you need to refer to verification.html as a File, then please ensure:
It has a distinct (absolute (ok!) or relative (good luck!)) address (in all target environments)!
Files and resources in Java
Your file is located inside the classpath. This is a special location within your source-code (here in package utils.emailTemplate.EmailVerificationTemplate). So we call it a classpath resource or simply resource.
Classpath resources
Usually those resources are destined to be published with your code, although they are actually not code.
In the Maven standard directory layout you would put them inside the special src/main/resources folder, separated from code.
Locating and reading resources
Resources are located relative from classpath using the classpath: schema. Since they are part of the sources, package-tree you can also locate them relative to one of your classes.
From your SendEmail class, the given template has relative path ../. So you can instantiate it as Resource building the URL using this.getClass().getResource(Stirng relativePath) from within your SendEmail class:
class SendEmail {
private final String relativePath = "../emailTemplate/EmailVerificationTemplate/verification.html";
// build the URL for the resource relative from within your class
public URL getVerificaitonEmailTemplateUrl() {
URL templateResourceUrl = this.getClass().getResource(relativePath);
return templateResourceUrl;
}
// load the resource
public InputStream getVerificaitonEmailTemplateStream() {
InputStream is = this.getClass().getResourceAsStream(relativePath);
return is;
}
}
Load a resource as input-stream getResourceAsStream(String name)
using the relative path from inside your class.
Alternative using Spring's special-purpose extension ClassPathResource:
private final String relativePath = "../emailTemplate/EmailVerificationTemplate/verification.html";
public String loadContentAsFile() {
ClassPathResource resource = new ClassPathResource(relativePath);
File file resource.getFile();
String content = new String(Files.readAllBytes(file.toPath()));
return content;
}
public InputStream getContentAsStream() {
ClassPathResource resource = new ClassPathResource(relativePath);
InputStream is resource.getInputStream();
return is;
}
Attention: This reading from a file works only if your resource is inside the file system. Not if your resource is inside a JAR:
This implementation returns a File reference for the underlying class path resource, provided that it refers to a file in the file system.
A safer and more robust way to read from the ClassPathResource is resource.getInputStream().
From InputStream to String
To fix your method, you could simply exchange the File related parts to InputStream:
public String readHTML(InputStream is) throws IOException {
String emailContent = "";
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
while ((emailContent = bufferedReader.readLine()) != null) {
stringBuilder.append(emailContent);
}
return stringBuilder.toString();
}
Or even simpler (see Baeldung's tutorial linked below):
String text = new BufferedReader(
new InputStreamReader(inputStream, StandardCharsets.UTF_8)) // choose the encoding to fit
.lines()
.collect(Collectors.joining("\n"));
Then re-use it to read from any stream (e.g. a File, a Resource, ClassPathResource, even a URL). For example:
public String loadTemplate(String relativeResourcePath) throws IOException {
InputStream inputStream = this.getClass().getResourceAsStream(relativeResourcePath)
String text = new BufferedReader(
new InputStreamReader(inputStream, StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining("\n"));
return text;
}
See also
Baeldung: Access a File from the Classpath using SpringBaeldung
Baeldung: Java InputStream to String
I have used InputStream to succesfully copy a file from one location to another:
public static void copy(File src, File dest) throws IOException {
InputStream is = null;
OutputStream os = null;
try {
is = new FileInputStream("C:\\test.txt");
os = new FileOutputStream("C:\\javatest\\test.txt");
byte[] buf = new byte[1024];
int bytesRead;
while ((bytesRead = is.read(buf)) > 0) {
os.write(buf, 0, bytesRead);
}
} finally {
is.close();
os.close();
}
}
The problem appears when I add a non-existing folder into the path, for example:
os = new FileOutputStream("C:\\javatest\\javanewfolder\\test.txt");
This returns a NullPointerException error. How can I create all of the missing directories when executing the copy process through Output Stream?
First, if possible I'd recommend you to use the java.nio.file classes (e.g. Path), instead of the File based approach. You will create Path objects by using a file system. You may use the default filesystem, if no flexibility is needed here:
final String folder = ...
final String filename = ...
final FileSystem fs = FileSystems.getDefault();
final Path myFile fs.getPath(folder, filename);
Then your problem is easily solved by a very convenient API:
final Path destinationFolder = dest.getParent();
Files.createDirectories(myPath.getParent());
try (final OutputStream os = Files.newOutputStream(myFile)) {
...
}
The Files.createDirectories() method will not fail if the directory already exists, but it may fail due to other reasons. For example if a file "foo/bar" exists, Files.createDirectories("foo/bar/folder") will most likely not succeed. ;)
Please read the javadoc carefully!
To check, if a path points to an existing directory, just user:
Files.isDirectory(somePath);
If needed, you can convert between File and Path. You will lose file system information, though:
final Path path1 = file1.toPath();
final File file2 = path2.toFile();
You could use Files.createDirectories:
Files.createDirectories(Paths.get("C:\\javatest\\javanewfolder"));
Also, you could use Files.copy to copy file )
I am using Maven and running a JUnit test on a static method that tries to read in a file using:
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(filename);
And then using new InputStreamReader(is) to use as a reader in another call. This works when filename is just a filename (e.g. file.csv) but when filename is a relative path (e.g. src/test/resources/file.csv), is ends up being null.
I need it to handle relative paths, because I'm running a test suite via JUnit that looks for resources with relative paths and these tests are coming from a JAR that I have no control over changing (i.e. I implemented a facade implementation class that the test suite uses to call its own tests with its own resources - they are out of my control).
Is there a way for this approach to work with relative paths, or some other way that I can find those resources on my classpath that the tests are looking for?
Running tests in maven, src/test/resources/ is (by default) "mapped" to the root of the class(loader)path, so in your case /file.csv is the correct absolute path of src/test/resources/file.csv.
To load "src/test/resources/file.csv" (Resource) successfully (which is comple nonsense), you should have this file (physically) available: src/test/resources/src/test/resources/file.csv, or respectively src/main/java(which would also be mapped to cp root) .../src/test/resources/file.csv
In your case is ends up being null because when a resource lookup is performed, the resources directory is entry point, so the complete path is expected to be test/resources/src/test/resources/file.csv or test/resources/src/test/resources/file.csv depending on how you run your tests.
The only reliable way you could achieve your goal is to take care about the correctness manually. Perhaps something like this:
static String getResourceFileName(String maybePath) {
Path path = Paths.get(maybePath);
if (path.getNameCount() > 0) {
return path.getFileName().toString();
} else {
throw new IllegalArgumentException("Can't derive filename given " + maybePath);
}
}
#Test
public void testSoq() throws Exception {
String fileName0 = getResourceFileName("file");
InputStream is0 = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName0);
String fileName1 = getResourceFileName("src/test/resources/file");
InputStream is1 = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName1);
String string0 = new BufferedReader(new InputStreamReader(is0)).readLine();
String string1 = new BufferedReader(new InputStreamReader(is1)).readLine();
assertEquals(string0, string1); // OK
}
Maybe you'll have to write it according to the specifics of your case (account for possible nested diretories etc.), but I really think that given your inputs may be of arbitrary nature, this won't get much simpler.
I have this on blog (in spanish)
http://lacuevadeyogui.blogspot.com/2015/04/diferencia-entre-uri-y-url.html
The problem in with the reference to file in src/test/resources
try this
URL url = getClass().getClassLoader().getResource("file.csv");
File f;
try {
f = new File(url.toURI());
} catch (URISyntaxException e) {
f = new File(url.getPath());
}
At the end, convert file to inputStream.
I want to read a file in my java class. My question is similar to this one, but there are two differences. first, I use a different project layout:
/src/com/company/project
/resources
In the resources folder I have a file called "test.txt":
/resources/test.txt
In the project folder I have a class test.java
/src/com/company/project/test.java
I want mu java class to be able to read the contents of test.txt in a STATIC METHOD. I've tried the following:
private static String parseFile()
{
try
{
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
String fileURL = classLoader.getResource("test.txt").getFile();
File file = new File(fileURL);
...
}
}
and the following paths:
File file1 = new File("test.txt");
File file2 = new File("/test.txt");
File file3 = new File("/resources/test.txt");
But they all throw a FileNotFoundException when I want to read the file. How can I correctly declare the path to my file in the snippet above with respect to my project setup and the fact that the method needs to be static?
You should use the class loader of the class which is in the same JAR as the resource instead of the TCCL. And then you need to specify the name of the resource with a full path. And it is typically not good to access those as files. Just open it directly for read (or copy it to a temp file if you need to):
InputStream is =
Project.class.getClassLoader().getResourceAsStream("/resource/test.txt");
BTW: if you simply want to open a file, you need to use a relative file name. This is searched relative to the start dir, which is normally the project main dir (in eclipse):
File resource = new File("resource/test.txt");
(but this wont work if you package it up as a JAR).
After endless trials, I gave up on ClassLoader and getResource methods of any kind.
Absolutely nothing worked, especially if the opening attempt was made from another project. I always ended up getting the bin folder instead of the src folder.
So I devised the following work around:
public class IOAccessory {
public static String getProjectDir() {
try {
Class<?> callingClass = Class.forName(Thread.currentThread().getStackTrace()[2].getClassName());
URL url = callingClass.getProtectionDomain().getCodeSource().getLocation();
URI parentDir = url.toURI().resolve("..");
return parentDir.getPath();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
return "";
}
}
The getProjectDir method returns the physical path of the project from which it was called, e.g. C:/workspace/MyProject/.
After that, all you need to do is concatenate the relative path in MyProject of your resource file to open the stream:
public void openResource() throws IOException {
InputStream stream = null;
String projectDir = IOAccessory.getProjectDir();
String filePath = "resources/test.txt";
try {
stream = new FileInputStream(projectDir + filePath);
open(stream);
} catch(Exception e) {
e.printStackTrace();
} finally {
if (stream != null)
stream.close();
}
}
This technique works whether the openResource method is static or non-static, and whether it is called from within the project or from another project on the build path.
It really depends on how your IDE generates output from your project. Typically, classloaders load resources relative to the invoking classes, but if treated right, 'resources' will just end up in the 'root' of your output folder hierarchy, and you can access them accordingly.
For example, if I recreate your code in IntelliJ IDEA, in a class called com/acme/TestClass.class, the following output structure is generated within the IDE when building. This assumes I have "test.txt" sitting in a folder I called "resources", and that folder is specified as being a "resources root":
/com
/acme
TestClass.class
test.txt
The text file ends up in the output folder's root, so accessing it is simple. The following code works for me when I attempt to load the file in a static method within TestClass:
ClassLoader cl = TestClass.class.getClassLoader();
InputStream is = cl.getResourceAsStream("test.txt");
The only thing not covered in the other answers is that your URL conversion to file might not work correctly. If the directories above your project contain a characters that must be decoded then your call to 'getResource("test.txt").getFile()' is not giving you a valid java.io.File path.
I load shader for openGL ES from static function.
Remember you must use lower case for your file and directory name, or else the operation will be failed
public class MyGLRenderer implements GLSurfaceView.Renderer {
...
public static int loadShader() {
// Read file as input stream
InputStream inputStream = MyGLRenderer.class.getResourceAsStream("/res/raw/vertex_shader.txt");
// Convert input stream to string
Scanner s = new Scanner(inputStream).useDelimiter("\\A");
String shaderCode = s.hasNext() ? s.next() : "";
}
...
}
Another method to convert input stream to string.
byte[] bytes;
String shaderCode = "";
try {
bytes = new byte[inputStream.available()];
inputStream.read(bytes);
shaderCode = new String(bytes);
}
catch (IOException e) {
e.printStackTrace();
}
I am building an application that must load the current class at runtime, and add it to a different .jar that I am creating. I have a method that adds files to a jar.
private static void add(File source, JarOutputStream target,
Manifest manifest) throws IOException {
BufferedInputStream in = null;
try {
String name = source.getName();
JarEntry entry = new JarEntry(name);
entry.setTime(source.lastModified());
target.putNextEntry(entry);
in = new BufferedInputStream(new FileInputStream(source));
byte[] buffer = new byte[1024];
while (true) {
int count = in.read(buffer);
if (count == -1)
break;
target.write(buffer, 0, count);
}
target.closeEntry();
} finally {
if (in != null)
in.close();
}
}
My problem is this: I can't seem to find out how to add the current class into a file at runtime. I have tried this:
File classFile= new File(getClass().getResource("MyClass.class").getPath());
but I get a null pointer exception. Any help would be greatly appreciated.
Don't try to get the class file as a File - just fetch the stream directly:
InputStream classFile = getClass().getResourceAsStream("MyClass.class");
You'll need to modify your add method to take a target name and an input stream, of course. (Potentially overload it, so you've still got the existing method available, which would just open the file, call the other method, then close the stream.)