I am testing a library (jar) that is using property (mytest.properties). They way the library (jar) loads the property is by doing
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream input = classLoader.getResourceAsStream("mytest.properties");
So what I want to test is what happens when the property file exist and when it does not exit. In order to test this I need to edit the property file once the JVM is started. I have tried doing that and does not work. Bellow is the code I tried to edit the property file but this always returns empty string.
Content of main_mytest.properties is:
a=hello world
b=hello java
Content of mytest.properties and empty.txt is empty.
""
My Class is:
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
public class MyPropertyFiles {
final static String resourcesPath = "./mytestproj/src/main/resources";
public static void main(String [] args) throws IOException {
Path source = Paths.get(resourcesPath + "/main_mytest.properties");
Path destination = Paths.get(resourcesPath + "/mytest.properties");
Path empty = Paths.get(resourcesPath + "/empty.txt");
try
{
Files.copy(source, destination, StandardCopyOption.REPLACE_EXISTING);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream input = classLoader.getResourceAsStream("mytest.properties");
StringWriter writer = new StringWriter();
IOUtils.copy(input, writer, "utf-8");
String theString = writer.toString();
System.out.println("!!!!!!!!!!!!!!!! The String: \n" + theString);
}
catch (Exception e)
{
e.printStackTrace();
}
finally {
Files.copy(empty, destination, StandardCopyOption.REPLACE_EXISTING);
}
}
}
After doing some digging I don't think reloading the files in the ClassLoader after the JVM has started is allowed.
Related
I have my XML file under the src/main/resources directory. My spring code looks like
import java.io.IOException;
import java.util.concurrent.atomic.AtomicLong;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import org.springframework.core.io.ClassPathResource;
import org.springframework.integration.xml.transformer.XsltPayloadTransformer;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
public class BdeApplicationController {
#GetMapping("/ping")
#ResponseBody
public String ping(#RequestParam(name="name", required=false, defaultValue="Stranger") String name) {
return myFlow();
}
private String myFlow() {
XsltPayloadTransformer transformer = getXsltTransformer();
return transformer.transform(buildMessage(getXMLFileString())).toString();
}
private String getXMLFileString() {
try {
return Files.toString(new ClassPathResource("XML1.xml").getFile(), Charsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
private XsltPayloadTransformer getXsltTransformer() {
return new XsltPayloadTransformer(new ClassPathResource("XSLT1.xsl"));
}
protected Message<?> buildMessage(Object payload) {
return MessageBuilder.withPayload(payload).build();
}
}
On running this code I get the following exception: -
java.io.FileNotFoundException: class path resource [XML1.xml] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/Users/user/Documents/project/target/bde-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/XML1.xml
Can you please suggest how can I fix this?
When you use resource.getFile() you look for the file in the file system, thats why it does't work when you runnit as a jar.
Try with a InputStream
String data = "";
ClassPathResource resource = new ClassPathResource("/XML1.xml");
try {
byte[] dataArr = FileCopyUtils.copyToByteArray(resource.getInputStream());
data = new String(dataArr, StandardCharsets.UTF_8);
} catch (IOException e) {
// do whatever
}
You have no File inside jar archive: use InputStream
Once you have the resource (via ClassPathResource) you should use getInputStream() to get its contents independently of where it is located. This way will work inside your IDE (actually a File there) and also when running the jar on the server (inside the jar archive, not exactly a File).
You need only modify your getXMLFileString() method so it uses the InputStream instead of the File:
private String getXMLFileString() {
String xml;
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
xml = reader.lines().collect(Collectors.joining("\n"));
reader.close();
} catch (IOException e) {
e.printStackTrace();
xml = null;
}
return new String(xml, Charsets.UTF_8);
}
Is it possible that to read a .java file as a file (using file path)from another class and call its method in this class ?
Lets takes a java class as
public Mylogic {
public static void test()
{
//some logic
}
}
Is there a way another java class can read Mylogic.java file as a file and execute test() method
?
Why I want this?
Once source code goes into application server , then if I have to add another class , I have to wait for complete deployment which takes time.If I am able to do this, I can keep a utility class ready in source code to read .java file from dir and execute it without any deployment, thus saving time.
This is for higher environment (production mode) so no exploded mode.
It is possible, if you have JDK instead of JRE when running the code, using javax.tools.JavaCompiler and a customized class loader:
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class LoadAndRun extends ClassLoader {
public Class findClass(String name) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
InputStream in = new FileInputStream("./" + name + ".class");
byte [] buff = new byte[4096];
while (true) {
int c = in.read(buff);
if (c == -1) break;
out.write(buff, 0, c);
}
return defineClass(name, out.toByteArray(), 0, out.toByteArray().length);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static void main(String [] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException {
// Try to get the system compiler
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
if (compiler == null) {
System.err.println("System java compiler not found.");
return;
}
// Prepare the java file to be compiled
String classname = "LoadAndRun" + System.currentTimeMillis();
File javaFile = new File(classname + ".java");
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(javaFile)));
writer.write("public class " + classname + "{\n");
writer.write("public static void test() {System.out.println(\"this is the test class:\"+"+classname+".class);}");
writer.write("}\n");
writer.close();
// Compile it!
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
compiler.getTask(null, fileManager, null, null, null, fileManager.getJavaFileObjects(javaFile)).call();
// Load and invoke static method
ClassLoader classLoader = new LoadAndRun();
Class cls = classLoader.loadClass(classname);
Method m = cls.getMethod("test");
m.invoke(null);
// Clean up
m = null;
cls = null;
classLoader = null;
System.gc();
javaFile.delete();
File classFile = new File(classname + ".class");
classFile.delete();
}
}
I need to make a change in .properties file in my Java project. This is later deployed as a jar and used by other Java project. But according to this, I see that we should not directly make the change instead create a new object. Where should we create that new object and how can we make sure that its changes are visible?
Yes that's correct if your properties files is inside a jar then you won't be able to directly change that properties file since its packaged and zipped up in an archive. Instead you can create/change the file placed on a drive and read it, I used "user.home" for an example which you can change it as your need, below is the code for the same:
package com.test.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PropertyFileReader {
private static final Logger LOGGER = LoggerFactory
.getLogger(PropertyFileReader.class);
private static Properties properties;
private static final String APPLICATION_PROPERTIES = "application.properties";
private static final String workingDir = System.getProperty("user.home");
private static File file = new File(workingDir, APPLICATION_PROPERTIES);
static {
properties = new Properties();
}
public static void main(String[] args) {
write("hello", "2");
System.out.println(read("hello"));
}
public static String read(final String propertyName) {
try (InputStream input = new FileInputStream(file)) {
properties.load(input);
} catch (IOException ex) {
LOGGER.error("Error occurred while reading property from file : ",
ex);
}
return properties.getProperty(propertyName);
}
public static void write(final String propertName,
final String propertyValue) {
try (OutputStream output = new FileOutputStream(file)) {
properties.setProperty(propertName, propertyValue);
properties.store(output, null);
} catch (IOException io) {
LOGGER.error("Error occurred while writing property to file : ", io);
}
}
}
I have most of it down but when I try to make the copy, no copy is made.
It finds the files in the specified directory like it is supposed to do and I think the copy function executes but there aren't any more files in the specified directory. Any help is appreciated. I made a printf function that isn't shown here. Thanks!
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Scanner;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.FileUtils;
import static java.nio.file.StandardCopyOption.*;
public class Stuff {
static String path, oldExtn, newExtn;
static Boolean delOrig = false;
private static void getPathStuff() {
printf("Please enter the desired path\n");
Scanner in = new Scanner(System.in);
path = in.next();
printf("Now enter the file extension to replace\n");
oldExtn = in.next();
printf("Now enter the file extension to replace with\n");
newExtn = in.next();
in.close();
}
public static void main(String[] args) {
getPathStuff();
File folder = new File(path);
printf("folder = %s\n", folder.getPath());
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.getName().endsWith(oldExtn)) {
printf(fileEntry.getName() + "\n");
File newFile = new File(FilenameUtils.getBaseName(fileEntry
.getName() + newExtn));
try {
printf("fileEntry = %s\n", fileEntry.toPath().toString());
Files.copy(fileEntry.toPath(), newFile.toPath(),
REPLACE_EXISTING);
} catch (IOException e) {
System.err.printf("Exception");
}
}
}
}
}`
The problem is that the new file is created without a full path (only the file name). So your new file is created - only not where you expect...
You can see that it'll work if you'll replace:
File newFile = new File(FilenameUtils.getBaseName(fileEntry
.getName() + newExtn));
with:
File newFile = new File(fileEntry.getAbsolutePath()
.substring(0,
fileEntry.getAbsolutePath()
.lastIndexOf(".")+1) + newExtn);
I have one file that is stored in C:/file.txt. The properties file location.properties contains only the path i.e C:/file.txt. I want to read the properties file, get the location , read the file and display everything.
But I am getting fileNotFound exception. Can anybody help me? This is my code:
package com.tcs.fileRead;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
public class ReadFile {
/**
* #param args
*/
public static void main(String[] args) {
Properties prop = new Properties();
try {
prop.load(new FileInputStream("location.properties"));
//prop.load(fileIn);
String loc = prop.getProperty("fileLoc");
System.out.println(loc);
BufferedReader buffer;
buffer = new BufferedReader(new FileReader(loc));
String line;
while((line =buffer.readLine())!= null)
{
System.out.println(line);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
This is the output:
"C:\file.txt"
java.io.FileNotFoundException: "C:\file.txt" (The filename, directory name, or volume label syntax is incorrect.)
at java.io.FileInputStream.<init>(FileInputStream.java:156)
at java.io.FileInputStream.<init>(FileInputStream.java:111)
at java.io.FileReader.<init>(FileReader.java:69)
at com.tcs.fileRead.ReadFile.main(ReadFile.java:29)
You have the path surrounded with quotes in your properties file, so you are trying to open "C:\file.txt" (which is not a valid path) instead of C:\file.txt.