Java: How to read file from different module? - java

I have a project with multiple maven modules
project/pom.xml
/external_services/pom.xml
/ifs/pom.xml
/src/test/java/
/MockIFSClient.java
/IFSClientTest.java
/src/test/java/resources/sample.json
/inventory/pom.xml
/business/pom.xml
/src/main/java/InventorySummary.java
/services/pom.xml
/src/main/java/InventorySummaryResource.java
/src/main/test/InventorySummaryResourceTest.java
MockIFSClient access sample.json as
try {
inventoryPriceDetails = mapper.readValue(new File(getClass().getResource("/getInventoryAndPriceResponse.json").getPath()), new TypeReference<List<InventoryPriceDetail>>() {
});
} catch (final IOException e) {
throw new RuntimeException("could not read resource :" + e.getMessage());
}
so IFSClientTest runs fins since they are in same package.
Problem?
InventorySummaryResourceTest calls MockIFSClient which tries to access the same code, but now it fails as
could not read resource :file:/Users/harith/IdeaProjects/inventory_api/external_services/ifs/target/ifs-1.0-SNAPSHOT-tests.jar!/sample.json (No such file or directory)
services/pom.xml has dependency as
<dependency>
<groupId>com.org.project.external_services</groupId>
<artifactId>ifs</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
Question
What change do I make to
new File(getClass().getResource("/getInventoryAndPriceResponse.json").getPath())
so that it can be accessed from different modules as well

This answer helped me getting it right
How to really read text file from classpath in Java
I changed my code then to
inventoryPriceDetails = mapper.readValue(getClass().getResourceAsStream("/getInventoryAndPriceResponse.json"), new TypeReference<List<InventoryPriceDetail>>() {});

Related

Java - Run SWT dependent Program without SWT installed

I have a java program, that includes org.eclipse.swt libraries like "Display" and "Shell"
One of the first things this program does is:
private void authenticationFlow() {
Display display = new Display();
Shell shell = new Shell(display);
final Browser browser;
//some other code here
}
I exported this program to a runnable jar file and can run it just fine on my PC.
However, when trying to run it on a PC without eclipse installed, the Program does not start. No Exceptions whatsoever. It simply exits and does not run the rest of the code.
I tried to debug by creating a bunch of alert boxes like this:
private void authenticationFlow() {
popAlertBox(AlertType.INFORMATION, "Nice", "Something happened", "Starting auth");
Display display = null;
try {
display = new Display();
} catch (Exception e) {
popAlertBox(AlertType.ERROR, "Oh oh", "Something went wrong", e.getMessage());
}
popAlertBox(AlertType.INFORMATION, "Nice", "Something happened", "created display");
Shell shell = new Shell(display);
popAlertBox(AlertType.INFORMATION, "Nice", "Something happened", "created shell");
final Browser browser;
GridLayout gridLayout = new GridLayout();
gridLayout.numColumns = 3;
try {
shell.setLayout(gridLayout);
} catch (Exception e) {
popAlertBox(AlertType.ERROR, "Shell error", "Could not instantiate Shell: ", e.getMessage());
}
//rest of code
And
private void popAlertBox(AlertType type, String title, String header, String contentText) {
Alert alert = new Alert(type);
alert.setTitle(title);
alert.setHeaderText(header);
alert.setContentText(contentText);
alert.setX(GUIMain.getStageX() + GUIMain.getWidth()*0.4);
alert.setY(GUIMain.getStageY()+ GUIMain.getHeight()*0.4);
alert.showAndWait();
}
I end up seeing the "Starting auth" AlertBox, and that's it, the program exits right after.
I never reach the "created display" AlertBox.
So I figured it has to do with SWT itself.
Now my question is
1. Is this really directly related to SWT or am I misunderstanding something.
2. If it is, how can I have this program run on a PC without eclipse installed?
EDIT:
I use maven for all dependencies
here is an image of my libraries, including swt
I have tried surrounding my method which is called in a try catch like so:
try{
authenticationFlow();
}catch (Exception e) {
popAlertBox(AlertType.ERROR, "oh oh", "Something went wrong", e.getMessage());
}
popAlertBox(AlertType.INFORMATION, "Nice", "Something happened", "If you see this then something is in fact happening. final popup");
And NONE of those two popups are displayed. Not the one inside the catch block and the one afterwards neither.
i added following dependencies inside my pom.xml:
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>swt</artifactId>
<version>3.3.0-v3346</version>
</dependency>
<dependency>
<groupId>org.eclipse.swt</groupId>
<artifactId>org.eclipse.swt.win32.win32.x86_64</artifactId>
<version>4.3</version>
</dependency>
and it is still not running on the pc, which does not have eclipse installed
If you want to run a program which is designed to have a ui written in SWT the best way is to provide the SWT library in the classpath of the application. This does not mean that you have to provide a whole eclipse. Eclipse is also just using SWT as the library for the ui.
Just grab the SWT jars and put them onto the classpath and the program should start presenting you a window which is expressed in the line Shell shell = new Shell(display).
Adding SWT using Maven:
<properties>
<swt.version>4.3</swt.version>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.swt</groupId>
<artifactId>org.eclipse.swt.win32.win32.x86_64</artifactId>
<version>${swt.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.swt</groupId>
<artifactId>org.eclipse.swt.win32.win32.x86</artifactId>
<version>${swt.version}</version>
<!-- To use the debug jar, add this -->
<classifier>debug</classifier>
</dependency>
<dependency>
<groupId>org.eclipse.swt</groupId>
<artifactId>org.eclipse.swt.gtk.linux.x86</artifactId>
<version>${swt.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.swt</groupId>
<artifactId>org.eclipse.swt.gtk.linux.x86_64</artifactId>
<version>${swt.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.swt</groupId>
<artifactId>org.eclipse.swt.cocoa.macosx.x86_64</artifactId>
<version>${swt.version}</version>
</dependency>
</dependencies>
This will add SWT for every platform. You can also just add the one you need to build for.
When building the application into a "fat-jar" please make sure all the dependencies are provided.

Maven: Access POM at runtime - How to get 'pom.xml' available from anywhere?

I want to access some information from the pom.xml to display in a Info dialog. So I googled and found this post:
public class MavenModelExample {
public static void main(String[] args) throws IOException, XmlPullParserException {
MavenXpp3Reader reader = new MavenXpp3Reader();
Model model = reader.read(new FileReader("pom.xml"));
System.out.println(model.getId());
System.out.println(model.getGroupId());
System.out.println(model.getArtifactId());
System.out.println(model.getVersion());
}
}
I implemented it in my tool, added
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model</artifactId>
<version>3.3.9</version>
</dependency>
to my pom and was happy that everything ran as expected when I run the tool from the project root directory with java -jar target\mytool.jar.
When I move to any other directory, e.g. directly into target and execute my tool with java -jar mytool.jar, I get:
java.io.FileNotFoundException: pom.xml (The system cannot find the specified file)
at java.base/java.io.FileInputStream.open0(Native Method)
at java.base/java.io.FileInputStream.open(FileInputStream.java:213)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:155)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:110)
at java.base/java.io.FileReader.<init>(FileReader.java:60)
Which is kind of comprehensible. How should the code know, where the pom.xml is located, as it is not a resource. Is there any way to work around that?
In the mean time I use the approach from this thread to obtain the version and artifactID.
The problem is that
Model model = reader.read(new FileReader("pom.xml"));
tries to read the POM from the directory where your program is executed. Normally, pom.xml won't get copied to target, but it is embedded in the resulting artifact. You can override and force Maven to copy the POM to the target directory if you want to (for your own project), but it won't help you for other Maven artifacts.
Most of the time, a Maven artifact will have the POM coordinates included in the JAR/WAR/EAR output. If you unpack such a file, you'll notice that there are two files stored under META-INF/maven/<groupId>/<artifactId>: pom.xml and pom.properties where the latter is far easier to parse than pom.xml but it doesn't include the dependencies.
Parsing the embedded pom.xml from the classpath (and not from disk) should work better for you, especially if you always run your program with java -jar target\mytool.jar. In your program, try this:
try (InputStream is = MavenModelExample.class.getClassLoader().getResourceAsStream("META-INF/maven/<your groupId>/<your artifactId>/pom.xml")) {
MavenXpp3Reader reader = new MavenXpp3Reader();
Model model = reader.read(is);
System.out.println(model.getId());
System.out.println(model.getGroupId());
System.out.println(model.getArtifactId());
System.out.println(model.getVersion());
// If you want to get fancy:
model.getDependencies().stream().forEach(System.out::println);
}
catch (IOException e) {
// Do whatever you need to do if the operation fails.
}
<your groupId> and <your artifactId> should be fairly static, but if you do relocate your artifact's coordinates, then you need to change this in your code as well.
problem is that :
read(new FileReader("pom.xml"))
works fine when you start your application from STS or else, but when you build your application as JAR the path of the pom.xml file change to :
META- INF/maven/${groupId}/${artifactId}/pom.xml.
for that, try this code :
MavenXpp3Reader mavenXpp3Reader = new MavenXpp3Reader();
Model model;
if ((new File("pom.xml")).exists()) {
model = mavenXpp3Reader.read(new FileReader("pom.xml"));
}
else {
// Packaged artifacts contain a META- INF/maven/${groupId}/${artifactId}/pom.properties
model = mavenXpp3Reader.read(new
InputStreamReader(Application.class.getResourceAsStream(
"/META-INF/maven/groupId/artifactId/pom.xml")));
}

How to use ROME in Intellij?

How can I set up my project in Intellij to use the ROME library to read a RSS Feed?
So far, I've developed the following:
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;
import java.net.URL;
public class ReadRSS {
public static void main(String[] args) {
String urlString = "http://news.ycombinator.com/"
boolean ok = false;
if (args.length==1) {
try {
URL feedUrl = new URL(urlString);
SyndFeedInput input = new SyndFeedInput();
SyndFeed feed = input.build(new XmlReader(feedUrl));
System.out.println(feed);
ok = true;
}
catch (Exception ex) {
ex.printStackTrace();
System.out.println("ERROR: "+ex.getMessage());
}
}
if (!ok) {
System.out.println();
System.out.println("FeedReader reads and prints any RSS/Atom feed type.");
System.out.println("The first parameter must be the URL of the feed to read.");
System.out.println();
}
}
}
But, I get multiple errors when running my code, mainly of the variant:
.. java:package com.sun.syndication.feed.synd does not exist..
How do I import the package in Intellij? Managed to import this my adding jar in my project structure.
But the next problem is: I can't access org.jdom.Document - though I have installed jdom in my project structure. The error I get is
Error:(16, 38) java: cannot access org.jdom.Document class file for
org.jdom.Document not found
How can I resolve this?
If you're using Maven or gradle add the dependency in your configuration file (ex. pom.xml in Maven) and do a build/install to download your dependencies. It should work fine after that. Dependency info is here: http://mvnrepository.com/artifact/rome/rome/0.9
Otherwise add the jar (downloadable from the link above) manually to your project. Look at the first answer in this question to see how to do this: Correct way to add external jars (lib/*.jar) to an IntelliJ IDEA project
I'm a developer of the ROME team. The latest version is ROME 1.5. It can be obtained from the central maven repository: http://search.maven.org/#artifactdetails%7Ccom.rometools%7Crome%7C1.5.1%7Cjar
The groupId has changed to com.rometools in v1.5.0.#
I highly recommend you to use Maven, Gradle or another build tool that is able to resolve transitive dependencies so you won't have to collect all dependencies manually.

NoSuchMethodError at org.apache.hadoop.hdfs.DFSInputStream

I have a really simple code in Java which reads data from hdfs
try{
InputStream s = new GzipCompressorInputStream(hdfsFileSystem.open(filePath), false);
ByteStreams.copy(s, outputStream);
s.close();
}
catch (Exception ex){
logger.error("Problem with file "+ filePath,ex);
}
Sometimes (not always) it throws me exception
java.lang.NoSuchMethodError: org.apache.commons.io.IOUtils.closeQuietly(Ljava/io/Closeable;)V
at org.apache.hadoop.hdfs.DFSInputStream.getBlockReader(DFSInputStream.java:1099)
at org.apache.hadoop.hdfs.DFSInputStream.blockSeekTo(DFSInputStream.java:533)
at org.apache.hadoop.hdfs.DFSInputStream.readWithStrategy(DFSInputStream.java:749)
at org.apache.hadoop.hdfs.DFSInputStream.read(DFSInputStream.java:793)
at java.io.DataInputStream.read(DataInputStream.java:149)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
at java.io.BufferedInputStream.read(BufferedInputStream.java:254)
at org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream.init(GzipCompressorInputStream.java:136)
at org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream.<init>(GzipCompressorInputStream.java:129)
[...]
On line below line:
InputStream s = new GzipCompressorInputStream(hdfsFileSystem.open(filePath), false);
I am using bellow maven dependency to load hadoop client:
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.2.0</version>
</dependency>
Does anybody knows how to fix this problem? Of cource I can change catch(Exception e) to catch(Error e), but it isn't a solution just workaround.
Looks like in yours classpath present several "commons-io.jar" with different versions.
Method "closeQuietly(Ljava/io/Closeable;)" appeared in version 2.0.
Sometimes "commons-io.jar" with older version loaded first, and exception appeared.
Classpath fix required.

Access resources from another jar file

I have a simple structure: A data jar file which contains a batch of data, and a service jar file, which runs a service using the data. To make the data easy to replace, I have them separate, and service.jar's classpath contains the directory which data.jar is in.
Within service.jar, I use getResource to load the data files. This works if the data files are directly within the folder, but fails when they are inside data.jar;
This fails:
all
+ globalclasspath
| + data.jar
| + mine.properties
+ daemons
+ service.jar
jsvc -cp globalclasspath:daemons/service.jar (...)
MyClass.class.getClassLoader( ).getResource( "mine.properties" ); // <-- null
But this works:
all
+ globalclasspath
| + mine.properties
+ daemons
+ service.jar
jsvc -cp globalclasspath:daemons/service.jar (...)
MyClass.class.getClassLoader( ).getResource( "mine.properties" ); // <-- not null
I don't want to change the classpath (unless I can change it to something generic which doesn't depend on the name of the data jar file), but I'm fine with changing the getResource string (I've tried /data/mine.properties and /data.jar/mine.properties to no avail). Is there a change I can make so that the resources can be loaded from within the jar?
Solution 1
Use a classpath wildcard.
jsvc -cp globalclasspath/*:daemons/service.jar (...)
See "How to use a wildcard in the classpath to add multiple jars?"
Solution 2
To read data in JARs not on the classpath, use URLClassLoader. The general algorithm is this:
Find the list of JARs in the globalclasspath directory.
Create a URLClassLoader from this list of JARs.
Look up the resource you want from the URLClassLoader instance.
To find JARs on the classpath, I used ResourceList from the StackOverflow article "Get a list of resources from classpath directory."
public class MyClass {
/**
* Creates a {#code URLClassLoader} from JAR files found in the
* globalclasspath directory, assuming that globalclasspath is in
* {#code System.getProperty("java.class.path")}.
*/
private static URLClassLoader createURLClassLoader() {
Collection<String> resources = ResourceList.getResources(Pattern.compile(".*\\.jar"));
Collection<URL> urls = new ArrayList<URL>();
for (String resource : resources) {
File file = new File(resource);
// Ensure that the JAR exists
// and is in the globalclasspath directory.
if (file.isFile() && "globalclasspath".equals(file.getParentFile().getName())) {
try {
urls.add(file.toURI().toURL());
} catch (MalformedURLException e) {
// This should never happen.
e.printStackTrace();
}
}
}
return new URLClassLoader(urls.toArray(new URL[urls.size()]));
}
public static void main(String[] args) {
URLClassLoader classLoader = createURLClassLoader();
System.out.println(classLoader.getResource("mine.properties"));
}
}
I ran the following command:
java -cp globalclasspath:daemons/service.jar MyClass
The terminal output:
jar:file:/workspace/all/globalclasspath/data.jar!/mine.properties
Have you tried getResourceAsStream as suggested here:
how-to-a-read-file-from-jar-in-java
You can now use the maven-resources-plugin to share resources between your jars!
In the pom.xml file of the source module/jar, add the following plugin:
<artifactId>DATA_MODULE_NAME</artifactId>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
</plugin>
</plugins>
</build>
This will tell maven to copy the contents of the resource folder along with the jar.
In the module you want to access those resources, add this to the dependencies in the pom:
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>DATA_MODULE_NAME</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
When you build your final jar, the resources from the source module will be copied in and available using getResource()

Categories