Recompiling Jar Dependencies - java

Let's say I have a project with a dependency on a class in JAR A, which subsequently has a dependency on a class in JAR B. To run the project, both jars need to be on the same class path. I have the source code for all three pieces - project, JAR A, and JAR B.
If I change the internals of the method in the class in JAR B without changing the API, do I need to recompile JAR A against it, or can I just drop it into the classpath of the project and go?
If I think about it, I don't think I would need to but I just want to double check. It's quite annoying copying the files around all the time when I'm just trying to add extra logging to JAR B which has no effect on JAR A.

I think you're correct: you'd simply re-create the JAR B that contained the new class and put it in the class path along with JARs A and C.

the code which populates Jar A only needs to be able to compile in order to create the jar.
If it relies on Jar B to compile, then Jar B needs to exist to the extent that it satisfies all of the references made to it by the code for Jar A.
The opposite is also true.
Once the code for Jar A has compiled, you can create it's jar and forget about it.
You can then change Jar B as much as you like as long as the API Jar A uses doesn't change.
EG:
In Jar B you define a function:
public class JarBClass
{
public static void doSomething()
{
throw new RuntimeException();
}
}
This compiles and you can create Jar B.
In Jar A you reference the function:
public class JarAClass
{
public static void useSomething()
{
JarBClass.doSomething();
}
}
This compiles and you can create Jar A, however running it would throw an exception.
You can update your Jar B code:
public class JarBClass
{
public static void doSomething()
{
System.out.println("all good");
}
}
This compiles and you can re-create Jar B. Jar A can run without exception.
However if you update Jar B and change the API:
public class JarBClass
{
public static void doSomething(String what)
{
System.out.println(what + " is all good");
}
}
You will need to modify and recompile Jar A.

Related

Import .jar libraries in VS Code

I need to use a .jar library, given by my teacher, to code for my Java class.
I am using VS Code, with the Java Extension Pack installed, for Java Project Management.
Can someone please explain me step by step how is it possible to import the .jar library, in order to use the classes defined by my teacher.
I have tried to copy the .jar in the lib folder and then add the reference, but it still did not work. I also know that I have to declare the classpath, but when I create the Java Project the .classpath file is not created automatically.
Thanks already!
First you should examine the classes in .jar file. Then you should load that class as,
Class<?> c1 = Class.forName("java.lang.String");
Then after you can use that class by calling that Class reference type variable.
See this example as well,
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
// get the Class instance using forName method
Class c1 = Class.forName("java.lang.String");
System.out.print("Class represented by c1: "+ c1.toString());
} }
Try to understand the code and implement proper solution to your project.
Good Luck.

Define a compile-time constant from an external value

I would like to define a version number in a main class in each jar file that is assigned at compile time, like what can be easily done in C with an #include statement with a value from an external file. I would like to only set a value in that external location once, so any jar files that get compiled/built until I change it gets that same value.
My first thought was to define it in a common class then simply reference it like this:
I create a Base.java file:
class Base
{
public final static String version = "1.2.3";
}
Then I compile Base.java and jar it up.
And then I create a Module1.java file:
class Module1
{
public final static String version = Base.version;
public static void main( String[] args )
{
Module1();
}
Module1()
{
System.out.println( "Module1: "+this.version );
}
}
But of course, this won't compile without importing Base class, so I insert this just before the Module1 class:
import Base;
And I compile Module1.java and jar it up, and execute it; and as expected it returns:
Module1: 1.2.3
So far so good. But then I edit the Base.java file and change the version value to something different, like, say, "1.3.0", then compile Base.java and jar it up.
And now I want to create a Module2.java file:
import Base;
class Module2
{
public final static String version = Base.version;
public static void main( String[] args )
{
Module2();
}
Module2()
{
System.out.println( "Module2: "+this.version );
}
}
And I compile and jar up Module2, and execute it it correctly returns:
Module2: 1.3.0
Also good. But as a sanity check I expect (want/hope) Module1 to return the same results as before, so I rerun Module1, but Bogus! It returns:
Module1: 1.3.0
Any advice on how to pull this off? So the version in a module remains as it was at compile-time, not set during each session at run-time?
In Java, the standard place for storing the version of a .jar file is the manifest file (META-INF/MANIFEST.MF), not a class file. Specifically, put this line there:
Implementation-Version: 1.2.3
See here for more details.
To access this information from your code, use the java.util.jar.Manifest class, and specifically the getMainAttributes() method.

gwt-test-utils does not find my entry point class

I am trying to get gwt-test-utils to work. I set up the project in the following way:
src/main/java : all the java source code
src/test/java : the test source code
src/test/resources : resource files for the tests
I am building my project with gradle and eclipse. Gradle uses these directories correctly by default and I added all three of them as source directories to Eclipse.
I have successfully built and run the project and was able to execute some plain old JUnit tests as well as a GWTTestCase, so I think I set up the project and its dependencies correctly.
Now I wanted to use gwt-test-utils for some more advanced integration tests. To do so I did the following:
Add the gwt-test-utils and gwt-test-utils-csv to my dependencies
gwtTestUtilsVersion = '0.45'
testCompile group:'com.googlecode.gwt-test-utils', name:'gwt-test-utils', version:gwtTestUtilsVersion
testCompile group:'com.googlecode.gwt-test-utils', name:'gwt-test-utils-csv', version:gwtTestUtilsVersion
Add a gwt-test-utils.properties file to the directory src/test/resources/META-INF with the following content:
path/to/my/module = gwt-module
Added a class that extends GwtCsvTest to a package in the src/test/java directory. It is modeled after the second example in HowToWriteCsvScenario from the gwt-test-utils project wiki, replacing occurrence of their example classes with mine. It looks like this
#CsvDirectory(value = "gwtTests")
public class LoginLogoutTest extends GwtCsvTest
{
#Mock
private MainServiceAsync mainService;
private AppController appController = new AppController();
#CsvMethod
public void initApp()
{
appController.onModuleLoad();
}
#Before
public void setup()
{
GwtFinder.registerNodeFinder("myApp", new NodeObjectFinder()
{
#Override
public Object find(Node node)
{
return csvRunner.getNodeValue(appController, node);
}
});
GwtFinder.registerNodeFinder("loginView", new NodeObjectFinder()
{
#Override
public Object find(Node node)
{
return csvRunner.getNodeValue(appController.getRootPresenter().getCurrentlyActiveSubPresenters().iterator().next().getView(), node);
}
});
addGwtCreateHandler(createRemoteServiceCreateHandler());
}
}
added a csv-file for configuring the test to src/test/resources/gwtTests with the following content
start
initApp
assertExist;/loginView/emailTextBox
I tried executing it via the Eclipse's Run As > JUnit Test and indirectly via gradle build (which executes all the test cases, not just this one). Both lead to the same error:
ERROR GwtTreeLogger Unable to find type 'myPackage.client.AppController'
ERROR GwtTreeLogger Hint: Check that the type name 'myPackage.client.AppController' is really what you meant
ERROR GwtTreeLogger Hint: Check that your classpath includes all required source roots
The AppController class is the entry-point configured in the module I configured in gwt-test-utils.properties, which makes me think that configuration works correctly and the rest of the setup (dependencies and all) work as well.
In an earlier version I used the same file as a subclass of GWTTestCase and created an AppController instance in the same way. That worked, so I'm pretty sure the class path is setup correctly to include it as well. I also tried changing it back to the previous version just now and it still works.
I have no clue why the class is not found. Is there anything gwt-test-utils does differently which means I need to specifically set the class path for it? Otherwise it should just work, since both gradle and eclipse know about all the relevant source folders and dependencies.

Type A is already defined error

I tried to search for the solution, but what I found I don't know how to apply in this situation. Please help me correct my code.
package Exercise;
public class Ex11_11 {
public static void main(String[] args) {
A a = new A(3);
}
}
class A extends B { // type A is already defined, A has a red underline
public A (int t) {
System.out.println("A's constructor is invoked");
}
}
class B { // type B is already defined, B has a red underline
public B () {
System.out.println("B's constructor is invoked");
}
}
Eclipse sometimes gets confused. If you choose Clean from the Project menu, it might fix these errors.
Well, the first thing to check is obviously whether or not you have another class called A in your file or in the same package.
I had the same problem. My computer was restarted remotely by I.T, and Eclipse did not shut down gracefully. I noticed there was an extra java file in my project that I didn't add. Deleted it, and now the error is gone.
In Project-> Clean, select "Clean projects selected below", select my project(s) and check "Start a build immediately" with "Build only selected projects".
Then problem will resolve.
Check if all your class files are saved. I've had this problem a few times: i define a class in a class file then move it in it's own one. Java gets confised, because it reads from the old version of the original file. Once you save it with the missing class definition in it and define the class in the new file all should be ok.
In your project you might have test directory with the same package structure and the same class name (for example copied without changing class name to *Test).
If none of the above solutions worked for you then it possible that Build Path is messed up. When you add a src to the build path make sure the src is not in the exclusion list. Place *(wild card) in the inclusion list and nothing in the exclusion list.
Make sure
Project | Build Automatically
is checked.
The main reason for this is that somewhere in same package you have already defined a class with name A.
which causes type A is already defined error.
check if there is any subclass or inner class named A
Have you added another project to the build path?
I had the same issue on my development environment (Eclipse).
My Maven application consumed other applications. On Eclipse, those projects were just added to the build path. One of them had the same package structure and class filename. Eclipse ends up thinking both the files which are physically different are in the same directory since the package structure and filename are same.
For example, let's say there are two files as below:
/Users/uname/home/proj1/com/app/proj/main/java/util/file1.java
and
/Users/uname/home/proj2/com/app/proj/main/java/util/file1.java
and lets say both have the package name
com.app.define.proj.util
If you add one of the project to the other, Eclipse would consider both the files to be in the same location.
I resolved by creating a JAR file out of the consumed application, adding it to the build path and removing the Eclipse project from build path.
rename the class name A to Aa or something and try to run.

How to build automatically different JARs from same code using Eclipse?

I have many more classes in the project but for now please consider only A, B and C classes.
abstract public class A {...}
public class B extends A {...}
public class C extends A {...}
Then later I have a code, say in class D, like this
A a = new B();
//A a = new C();
//use a's methods
So my question now is how to easily configure in Eclipse building of two separate JARs. First one should have B.class included and C.class excluded and code as A a = new B(); The second one should have C.class included and B.class excluded and code as A a = new C();
I do not know many things about Ant and Maven. Do I need to use them in this case?
Maybe, something wrong with my design, if so, please let me know.
What you want to is mainly a code loading problem, not an Ant problem.
Just the two statements you presented for creating a new class instance:
A a = new B();
A a = new C();
The constructors are called using static code. Ant can not change the code, therefore the only way with Ant I see is generating a Factory class with Ant as part of the build process, depending if A or C is included into the JAR
But that would result in a project that can no longer be used directly in Eclipse as the original source code in the Eclipse project misses the factor class.
A IMHO better approach is dynamic class loading (may be combined with reflection). You can automatically search for classes that extend A or you add a configuration file/info to the JAR specifying which class to create (e.g. properties file).
Place the properties file in the src folder with the Java file and load it via this.getClass().getResource("myclass.config");
The config file can contain the class name that should used for creating a new instance.
The following code snipped assumes that B and C both have a public constructor that does not take any argument:
String classNameToLoad = ... // loaded from config file example "mypackage.B"
final Class<?> c = Class.forName(classNameToLoad);
final Class<? extends A> ac = c.asSubclass(A.class);
final Constructor<? extends A> a_ctor = ac.getConstructor();
final A a = a_ctor.newInstance();
In your eclipse you if you right click your project, you will have an option Export
Click on that, and select jar, then name the jar, select the classes you want in it.
Repeat this for the other jar.
check this http://help.eclipse.org/juno/index.jsp?topic=%2Forg.eclipse.jdt.doc.user%2Ftasks%2Ftasks-33.htm
The easiest way to do this would be to have 3 separate Java projects in Eclipse. Based on your example, that would be
B code project
C code project
A common code
Eclipse allows you to reference the bin directory of another project from your project in the build path.
Then you can export (or use Ant) the B and C projects as separate projects.

Categories

Resources