I have been trying to compile one perticular class of my project with a higher compiler compliance level than the rest of the project but i cant figure out how to do it.
I am compiling the project in Java 6 (for compatibility reasons) and there is a single class which requires Java 8 and will only be instantiated in the code (With reflection) if the version of Java it is running on is >=8.
The problem is that the class which is in Java 8 obviously does not compile in Java 6 so i would like to ask, if there is a way in Eclipse to compile this single class with Java 8 when the project is exported to a Runnable Jar.
There is always the option of compiling the project in Java 6 (without the java 8 class), exporting, and manually compiling that class with Java 8 and then inserting in to the Jar file manually which works fine but is not very convenient.
For example lets suppose that the project consists of the following:
A Common Interface:
public interface CommonInterface {
public void foo();
}
A Java 8 class:
public class Java8Class implements CommonInterface {
#Override
public void foo() {
Arrays.asList("Some", "Java", "8", "code").forEach(System.out::println);
}
}
A Java 6+ class:
public class Java6PlusClass implements CommonInterface {
#Override
public void foo() {
List<String> list = Arrays.asList("Some", "Java", "6", "code");
for (String s : list) {
System.out.println(s);
}
}
}
And the main program class:
public class Selector {
public static void main(String[] args) throws ReflectiveOperationException{
CommonInterface ci = getCorrectInstance();
ci.foo();
}
private static CommonInterface getCorrectInstance() throws ReflectiveOperationException {
String version = System.getProperty("java.version");
Matcher m = Pattern.compile("\\d\\.(\\d)\\..+").matcher(version);
String clazz = null;
if (m.find()) {
int jv = Integer.parseInt(m.group(1));
if (jv == 8)
clazz = "Java8Class";
else if (jv >= 6)
clazz = "Java6PlusClass";
}
if (clazz == null)
return null;
return (CommonInterface) Class.forName(clazz).newInstance();
}
}
In the above example, is it possible to configure Eclipse such that all classes apart from "Java8Class" compile with Java 6 compliance and the "Java8Class" compiles with Java 8 compliance?
Thanks.
You cannot do this in Eclipse, and I don't believe what you are trying to achieve is a good idea.
Here's what you could do instead:
Change the code of this Java 8 class to something equivalent in Java 6 (if possible).
Create a new project with this single class, and compile it with Java 8 compliance level. Specify this new jar file on the command line when launching your application, and it should do the trick.
Have 2 different versions of your application (one that is Java 8 compliant, and the other being Java 6 compliant), and launch the correct one based on the Java version available on the system.
I'm not totally sure if that second option would work simply by putting the jar file in the classpath in the cases where your program is executed using a Java 6 JRE. You might have to do some class loader trickery if it fails to start.
Related
Let’s say that in hypothetical Java version X.1 we have a class in the standard library (or third-party with backwards compatible API and version tied to Java version)
public class String {
private final byte[] bytes;
//...
}
and in Java X.2 it has changed internally
public class String {
private final char[] chars;
//...
}
We also have a class that accesses String class field, which is a part of a plugin for a server
public class Accessor {
public static Field getField() throws ReflectiveOperationException {
return String.class.getDeclaredField(“bytes”);
}
Server runs on Java X.2, plugin was compiled using Java X.1 and loaded at runtime
What will happen? Which String class will the Accessor see? If it will be X.1 then what happens if server and plugin share a String?
If it will be X.2 is there a way to force a specific version at compile-time or in the package configuration, or at least determine from which Java version the currently visible String class comes from?
If we talk about java.lang.String class or any other class from jvm then it is usually a part of a JVM where the code is run. And in your case you'll get version x.2.
But if we talk about custom compiled class from a 3rd party library then it depends on the target version that was specified during compilation of that class. In your case it might be version 1.x.
I have googled and searched the best I could, but I still could not find an solution. Maybe my search queries was not correct or details.
I do know there are a number of API changes from java 8 to 10. The jdk structure for 8 to 10 has also a significant changes.
Problem:
I have the following dependencies:
Project A --> Project B --> Project C
Some class in project A will call classes in Project B and B will call C. In Java 8 there were no issues.
After I upgrade to Java 10, a NoClassDefFoundError exception occurs.
I found two ways to overcome the issue
Project A now also depends on Project C
In the Java Build Path tab --> Order and Export tab, checked the Project C checkbox.
Question
Is there a better way to resolve my problem instead of using the solutions I found? Because my project codes are huge and it will take a lot of time to do so.
I would also like to know the underlying cause of the problem if possible.
Code:
ClassA.java (Project A):
package pkg;
public class ClassA {
public ClassA() {
new ClassB();
}
public static void main(String[] args) {
new ClassA();
}
}
ClassB.java (Project B)
package pkg;
public class ClassB {
public ClassB() {
callClassC();
}
public void callClassC() {
ClassC classC = new ClassC();
String info = classC.getInfo();
System.out.println(info);
}
}
ClassC.java (Project C)
package pkg;
public class ClassC {
public String getInfo() {
return "Class c info";
}
}
I also exported a eclipse workspace for my issue. I created this workspace using an older version of eclipse and java.
I can reproduce this. The code compiles, but you get an error when executing.
This is an eclipse bug.
Please report it at https://bugs.eclipse.org.
A possible workaround: Edit the run configuration, go to the Dependencies tab, use Add variable string with the value ${project_classpath}
I am new to scala. I have a requirement to execute the scala class using java.
My exact requirement is: I need to pass the entire scala class (file) as an argument to the java jar. That jar should read the scala code and execute it. I have searched many sites but did not find the appropriate answer. Is there any way to do the same?
Thank you in Advance.
Besides of your motivation to do that, it is for sure possible (I did it using my IDE - sbt project)
I just made scala class as below:
import com.google.common.base.Objects
class Car(_color: String, _valid: Boolean) {
val color: String = _color
val valid: Boolean = _valid
override def toString = Objects.toStringHelper(this).add("color",color).add("valid", valid).toString
}
After that I made class with main method to test it.
public class Test {
public static void main(String[] args) {
Car test = new Car("test", true);
System.out.println("test = " + test);
}
}
It compiled without any problems and the result was like below:
test = Car{color=test, valid=true}
Scala has its own compiler scalac whereas java uses javac. Since scalac compiles to class file that java can read and assuming that you are only using java libraries in the class then you can load the class in java. So what you need is to call scalac to compile the scala file and then load the generate class file using ClassLoader
I'm need to create an api for what will be a suite of primarily java applications. I need to do this quickly however, and at the moment I'm most comfortable writing in groovy. My question is, can I create this api in groovy, and use it in java applications without any special hoops?
That is, can I create a jar from my groovy classes and methods, and have the java applications use this jar as though it were created in java?
Yes, you can. Just compile using gradle, ant, whatever, to generate a jar. The resulting jar will depend on Groovy runtime jar and modules, if any. Groovy compiles to bytecode, so Java doesn't really know the differente. Only dynamic stuff won't work.
MyLib.groovy:
class MyLib {
def string
MyLib(string) {
this.string = string
}
String yell() {
string.toUpperCase() + "!!!"
}
}
Compiled:
$ groovyc MyLib.groovy
Writing the Java class which uses the Groovy one, TestMyLib.java:
public class TestMyLib {
public static void main(String[] args ) {
MyLib my = new MyLib("john doe");
System.out.println(my.yell()); // prints JOHN DOE!!!
}
}
Compiling:
$ javac TestMyLib.java
And execution:
$ java -cp $GROOVY_HOME/embeddable/groovy-all-2.1.8.jar:. TestMyLib
JOHN DOE!!!
I'm trying to run ajc compiler from Java (not from Maven or Ant!). The question is which Maven dependency do I need and which class is an entry point? The best option I have now is org.aspectj.tools.ajc.Main from org.aspectj:aspectjtools:1.7.2. Am I right?
Yes. In your Java project you need aspectjrt.jar (for the runtime) and aspectjtools.jar (for the compiler) on the class path. Then you can build an AspectJ project and create a JAR file containing aspects and classes like this:
import org.aspectj.tools.ajc.Main;
public class AjcRunner {
public static void main(String[] args) throws Exception {
String[] ajcArgs = {
"-sourceroots", "c:\\my\\aspectj_project\\src",
"-outjar", "my_aspects.jar"
};
Main.main(ajcArgs);
}
}
Afterwards you can test the result on the console like this, assuming you have a class Application with a main method:
java -cp C:\path\to\aspectjrt.jar;my_aspects.jar Application