How to get all files in directory in the classpath - spring-boot

Is there a way using ResourceLoader to get a list of "sub resources" in a directory in the jar?
For example, given sources
src/main/resources/mydir/myfile1.txt
src/main/resources/mydir/myfile2.txt
and using
#Autowired
private ResourceLoader resourceLoader;
I can get to the directory
Resource dir = resourceLoader.getResource("classpath:mydir")
dir.exists() // true
but not the files within the dir. If I could get the file, I could call dir.getFile().listFiles(), but
dir.getFile() // explodes with FileNotFoundException
But I can't find a way to get the "child" resources.

You can use a ResourcePatternResolver to get all the resources that match a particular pattern. For example:
Resource[] resources = resourcePatternResolver.getResources("/mydir/*.txt")
You can have a ResourcePatternResolver injected in the same way as ResourceLoader.

Based on Bohemian's comment and another answer, I used the following to get an input streams of all YAMLs under a directory and sub-directories in resources (Note that the path passed doesn't begin with /):
private static Stream<InputStream> getInputStreamsFromClasspath(
String path,
PathMatchingResourcePatternResolver resolver
) {
try {
return Arrays.stream(resolver.getResources("/" + path + "/**/*.yaml"))
.filter(Resource::exists)
.map(resource -> {
try {
return resource.getInputStream();
} catch (IOException e) {
return null;
}
})
.filter(Objects::nonNull);
} catch (IOException e) {
logger.error("Failed to get definitions from directory {}", path, e);
return Stream.of();
}
}

Related

How to mock Files.copy method in JUnit

I am using some of the methods of Files class like (delete, copy methods) to do upload and delete of file. Below is the code to perform these operations.
public String uploadFile(MultipartFile file) {
try {
String fileName = file.getOriginalFilename()
// Copy file to the target location (Replacing existing file with the same name)
Path targetLocation = Paths.get("uploadPath" + File.separator + StringUtils.cleanPath(fileName));
Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
return fileName;
} catch (IOException ex) {
throw new FileStorageException("Not able to upload", ex);
}
}
But for this source code I am not able to write JUnit tests because not able to mock Files class. For mocking final classes we can use PowerMock which supports to mock static and final methods. But here if I do using PowerMock still it is not mocking. I am using Spring Framework 5.2.1.RELEASE , Is there any change in JUnit with this version to mock final classes or methods? Or can any one help me on writing the unit tests for this code (versions I am using Spring Framework 5.2.1 and JUnit4.12).
Mocking static and final classes is indeed possible only with tools like PowerMock or PowerMockito, and its not related to JUnit or Spring frameworks.
I think you should not Mock Files.copy operation.
Instead consider the following strategy:
Define an interface for working with files, a kind of DAO but for file system:
public interface FileSystemDAO {
void copy(InputStream is, Path target, StandardCopyOption ... options);
}
public class FileSystemDAOImpl implements FileSystemDAO {
void copy(InputStream is, Path target, StandatadCopyOption ... options) {
Files.copy(...)
}
}
Now use dependency injection in all the places that work with files (if you're using spring as you've said - define FileSystemDAOImpl as a bean).
class MySampleUploadService {
private final FileSystemDAO fileSystemDao;
public MySampleUploadService(FileSystemDAO dao) {
this.fileSystemDao = dao;
}
public String uploadFile(MultipartFile file) {
try {
String fileName = file.getOriginalFilename()
// Copy file to the target location (Replacing existing file with the same name)
Path targetLocation = Paths.get("uploadPath" + File.separator +
StringUtils.cleanPath(fileName));
fileSystemDao.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
return fileName;
} catch (IOException ex) {
throw new FileStorageException("Not able to upload", ex);
}
}
}
Now with this approach you can easily test the Upload service by mocking the FileSystemDao interface.

What happen when move=null in camel route?

In my Spring Camel app, I try to move or delete a file base on the destinationFolder property. If destinationFolder=null, I want the file to be deleted. If destinationFolder!=null, I want the file to be moved to destinationFolder.
String destinationFolder;
//In the Camel routeBuilder:
from("file://C:/folder1?move=" + destinationFolder)
What will happen in destinationFolder is null? Does the file get move to default location?
When I set destinationFolder=null, I see the file is deleted in folder1.
If you set the move option then the file component will move the file, you cannot set it to null and then have it automatic delete the file. By default the file is moved to a folder named .camel.
So either set delete=true or set move to some folder name to move the files.
First, you should know when to use "move", "delete" &"noop" and how it will works in Apache camel
Note :1) If your destination path is not existed then file will delete automatically.
Note :2) If you are not used "noop=true" in Camel URL then file file will delete(if your destination path is null)
Reference : - enter link description here
Basic Test Code:
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
public class SFTPTest {
public static void main(String[] args) throws Exception {
DefaultCamelContext ctx = null;
try{
ctx = new DefaultCamelContext();
ctx.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
String filepath = "file:///camelexample/?fileName=test.txt&move=null";
from(filepath)
.log("File processed");
}
});
ctx.start();
Thread.sleep(5000);
ctx.stop();
}catch (Exception e){
System.err.println("Exception is : "+e.getLocalizedMessage());
}finally {
try{
ctx.stop();
}catch (Exception e){
System.err.println("Exception is : "+e.getLocalizedMessage());
}
}
}
}

List Files from Templates Directory in Spring Boot

I would like to generate a blog posts overview. For that I want to read the html files from a folder inside the templates folder in the resources folder where Spring Boot stores its templates.
I tried that but it doesnt return an error but also list no files.
What is the way to go here?
Thanks
#Controller
public class Route {
#Autowired
private ResourceLoader resourceLoader;
#RequestMapping("/")
public String home() throws IOException {
final String path = "templates/blog";
final Resource res = resourceLoader.getResource("templates/blog");
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(res.getInputStream()))) {
reader.lines().forEachOrdered(System.out::println);
}
return "blog/a";
}
}
#Controller
public class Route {
#Value("classpath:templates/blog/*")
private Resource[] resources;
#RequestMapping("/")
public String home() throws IOException {
for (final Resource res : resources) {
System.out.println(res.getFilename());
}
return "blog/a";
}
}
did the trick to me.
You should be able to achieve this using NIO2.
In order for NIO2 to work, it requires the concept of FileSystem, and one can be created from the jar URI. Then this file system can be used with Files/Paths.
The code below contains two branches - the first handles loading the files from inside Jar, the second branch - when the code runs from IDE or via "mvn spring-boot:run".
All streams are being used via try-with-resources so they will be auto-closed.
The find function starts from the top of the file system and recursively searches for html files.
public static void readFile(String location) throws URISyntaxException {
URI uri = Objects.requireNonNull(ReadFromJar.class.getClassLoader().getResource(location)).toURI();
if (uri.getScheme().equals("jar")) { //inside jar
try (FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap())) { //build a new FS that represents the jar's contents
Files.find(fs.getPath("/"), 10, (path, fileAttr) -> // control the search depth (e.g. 10)
fileAttr.isRegularFile() //match only files
&& path.toString().contains("blog") //match only files in paths containing "blog"
&& path.getFileName().toString().matches(".*\\.html")) // match only html files
.forEach(ReadFromJar::printFileContent);
} catch (IOException ex) {
ex.printStackTrace();
}
}
else { //from IDE or spring-boot:run
final Path path = Paths.get(uri);
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(path)) {
dirStream.forEach(ReadFromJar::printFileContent);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void printFileContent(final Path file) {
try {
System.out.println("Full path: " + file.toAbsolutePath().toString());
Files.lines(file).forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}

Spring MVC controller create file path

I want to create file path in controller
Already created file path and it's working
try {
Files.write(Paths.get("D:\\app\\app\\java.ini"), data, StandardCharsets.UTF_8, StandardOpenOption.CREATE);
} catch (IOException e) {
e.printStackTrace();
}
Now i want to change this D:\\app\\app\\java.ini and i want to create like resources/java.ini
I don't to give any system full path.
Thanx
The sample code below shows the example that you need:
public class MyClass
{
public static void main(String[] args) {
String test = MyClass.class.getProtectionDomain()
.getCodeSource().getLocation().getPath();
System.out.println(test);
}
}
Assuming that the method you are running is called MyClass, you can have this snippet inside your Java method:
try {
String location = MyClass.class.getProtectionDomain()
.getCodeSource().getLocation().getPath() + "resources/java.ini");
Files.write(location, data, StandardCharsets.UTF_8, StandardOpenOption.CREATE);
} catch (IOException e) {
e.printStackTrace();
}

ResourceLoader is throwing exception

I have a code like follows
public LocalFileStorage(String storageUrl, Resource storageDirectory) {
this.storageUrl = storageUrl;
try {
this.storageDirectory = storageDirectory.getFile();
this.storageDirectory.deleteOnExit();
this.storageDirectory.createNewFile();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
I call the class the follows.
private ResourceLoader resourceLoader; // from spring
LocalFileStorage pictureStorage = new LocalFileStorage(Url+ "/resources/", resourceLoader.getResource("/resources/"));
call to
resourceLoader.getResource("/resources/")
throws exception. I thought ResourceLoader loads directory also because after all directory is also a file.
My structure
Typically, only anything inside /WEB-INF/classes, /WEB-INF/lib, /WEB-INF/... will be added to the classpath and accessible through ClassLoader.getResource(). The folder you are trying to access is not in WEB-INF and will therefore not appear in the classpath.
Assuming you are using something similar to Maven, you should put resource files under /src/main/resources. When your project is built, those files will end up in WEB-INF/classes.

Resources