Is it possible to compile a java file without providing its dependencies? - java

There is a java file, which has some dependencies jars. But now, I don't have those jars, and I have to compile it to a .class file.
Is it possible to do this?
UPDATE
Thanks for your answers.
At first, I thought we can create some stubs for the missing dependencies, that's easy but boring. Since we can create the stubs without missing stubs to make the compiler happy, why can't we make a tool do it automatically? The tool doesn't need to create stubs, but reads the java file, collects informations, and then builds the .class files.
But if the "import" statements in the java file contain "*", that will be a problem:
import aaa.*
import bbb.*
public class Hello {
World world;
}
We don't know if the class "World" is under package "aaa" or "bbb". If we are not familiar with the missing dependencies, we even don't know how to create a stub for the class "World".
But if the "import" statements are clear, I think it's possible, but maybe no one will write such a tool

You could go crazy and hand craft the required dependencies as stubs that do nothing except keep the compiler happy.

No. Sorry. You'll need all dependncies in the classpath to compile.

No. But you could provide stubbed-out versions of the dependency class files, if it is only a handful of classes that the code your are trying to compile uses directly.
Then in theory if you take the .class file that compiles and place the real dependencies on the classpath with it your app will work using the correct (non-stubbed-out) dependency classes.

Before any file is compiled it always looks up for any dependencies.
but you said you dont have those jars!!!
see if you can remove the dependencies relation for that project/file and then try to compile it. give it a try!

Related

How to import packages from the external Library in Java?

I'm a n00b coder. I found an interesting library and trying to start toying with it. Which is not going great. This library is from 99' and uses JUnit (which I'm unfamiliar with) so there is a lot of confusing stuff. But it seems like the source of my failing even more elementary. Namely I have troubles importing packages.
This library has a test called StandardEvalTest.java. I moved to it to main Java directory and now I'm trying and failing to launch it using JUnit.
This package path org.pokersource.game.Deck goes directly from the directory where the test StandardEvalTest.java sits.
I also added the main java directory to the PATH environmental variable. Which as I assumed will allow import to locate the package.
None of those two things help. Also I was suspecting that maybe Deck.java and Deck.class are not enough and I have to do some work to create a package from it. But as far as I can say from Oracle doc the only thing needed is a package name in the header. Which seems to be present.
So I'm out of moves. Please help!
PS: Some additional info inspired by #Dhrubo 's answer:
The test I'm trying to run indeed sits in the main java folder of the library. (I moved it here hoping that when running from here it would be easier to find the package)
If I'm trying to compile the test instead of running it with JUnit he seem to fail to find JUnit classes and other JUnit related stuff.
[Oh OK I'm an idiot! Dont't mind me]
You should include the package while running StandardEvalTest.java as below
javac -cp [classpath] org.pokersource.game.StandardEvalTest.java
and run it from package root directory, I am assuming it is custom java file that you want to compile. You run directory should be parent of your package directory.
** I also see, you are trying to compile StandardEvalTest.java instead of Deck.java ... then check your StandardEvalTest.java file whether it exists in desired location.

Creating Java Packages in IntelliJ

I've been using Eclipse for a while and I'm having trouble understanding what's going on with my first project in IntelliJ. I've read the documentation, and searched other questions, but I still can't seem to grasp it. I think there is something wrong with my project structure. This is what my structure currently looks like;
I'm trying to run the JavaForLoop class, but whenever I do, compilation fails because I have errors in the StringMethods class of the strings package. My question is why would that prevent compilation if the two classes are in separate packages? Neither class uses the other, and they both have the appropriate package declaration statements. With a similar structure in Eclipse, this would work. Should I be using a different project structure?
By default IDEA adds Build Configuration which is executed before launch and includes following steps (taken from here):
Compiling source code in the source path of a module and placing results to the output path.
Compiling source code in the test path of a module and placing results to the test output path.
Creating copies of the resource files in the output path.
Reporting problems in the Messages tool window.
check if it's your case in Edit Configuration screen and if so, remove it.
To use a class from a different package you must declare a import statement to the class.
In your JavaForLoop.java add the import before the class statement (and after package declaration where its the case)
//package ...
import strings.StringMethods;
//public class JavaForLoop { and the rest of the code
Intellij uses regular javac, which will fail to compile if you have errors anywhere in the code.
Eclipse has it's own compiler, that allows to compile and even run code that has compilation errors, causing a runtime exception if any part of the code that has errors is run. This allows you to run parts of the code that work even if other pieces of code are failing.
The simple solution is to resolve your compilation errors. You can also use the eclipse compiler with Intellij, but I've never done this so I can't comment on how well it works.

How to create class that will only receive dependency in classpath at runtime?

I work for a company that distributes our product as a jar file, and I'm trying to write something that will be able to test past versions of these jars with various inputs. Ideally, I could then run the test framework like
java -jar testframework.jar -cp "version1.jar"
or
java -jar testframework.jar -cp "version2.jar"
and get different outputs. Since the methods that take in input are set in stone, I figured I could make the dependency on our product scope "provided" or "runtime" in maven, and then call input methods on whatever version of the jar was provided in the classpath. Something like this:
<dependency>
<groupId>com.ourCompany</groupid>
<artifactId>ourProduct</artifactId>
<scope>provided</scope>
</dependency>
and then in the main TestFramework class:
public static void main(String[] args) {
ProductClass.doSomething();
}
However, I'm getting a compilation error that the doSomething method doesn't exist. I imagine I'm misunderstanding exactly what "provided" and "runtime" mean with respect to maven dependencies, but I haven't been able to find any resources that explain my mistake. Does anyone know how I can do what I'm trying to do?
ProductClass definitely exists within ProductJar. It has no
problem importing the class, just calling the method doSomething. And
I'm getting that error when I use provided scope.
Because you are confirming that the JAR exists, the issue seems like with the version of the JAR file you are pointing to, so specify the <version>X</version> (in which the doSomething method exist) as well for the <dependency> and should solve the problem.
I'm misunderstanding exactly what "provided" and "runtime" mean with
respect to maven dependencies
provided and runtime scopes are completely different, they are for two different purposes.
provided scope means that the dependency is required during compile and test time (but, the dependency JAR will not be bundled as part of the JAR packaging, so the JAR should be available in the container classpath)
runtime scope means that the dependency is required only during execution of the program, not at compile time.
The dependencies always need to be available at compile time. Otherwise, how would the compiler be able to know if your code is valid or not? Check that the version you've declared in the dependency does indeed have the doSomething method you want to use. If not you will need to change the version to one that does have that method.

Force IntelliJ to Keep Same-Package Import Statements

Given the following package structure:
| com.java.package
| A.java
| B.java
And the following code in B.java
package com.java.package
public class B {
private final A aObject = new A();
public void foo() {
aObject.foo();
}
}
Is is possible to include the following import line?
import com.java.package.A;
Rationale: I am writing scripts to parse file dependencies for my build system using import statements, and when dependencies are intra-package (within the same package), Android Studio (IntelliJ) will "optimize out" my import statements and remove them from the file.
Is there a way to force the IDE to keep my intra-package import statements?
As long as you never optimize imports, then it'll probably stay. There is a setting somewhere (varies by version) that allows you to specify how many imports of the same package before it optimizes to '*', you'll want to make that a huge number.
Ultimately, I expect IJ to optimize it away somewhere when you don't expect. Even though it does seem to compile, it looks/feels wrong and someone else unaware of your external dependency is going to chomp it.
Better solution is to make your scripts smart enough to recognize intra-package classes as all dependencies - because implicitly they are - and just simply the problem. What you've proposed doesn't sound like a workable solution
One answer is to skip trying to parse Java for imports and use the jdeps command which is part of the JDK. jdeps works on .class files so it will work on java and kotlin (and Scala, etc). I'm reviewing the emerge-vis app, and it has the same problem with same-package imports.
The jdeps command shows the package-level or class-level dependencies of Java class files. The input class can be a path name to a .class file, a directory, a JAR file, or it can be a fully qualified class name to analyze all class files. The options determine the output. By default, jdeps outputs the dependencies to the system output. It can generate the dependencies in DOT language (see the -dotoutput option).

Program to obfuscate files before compilation?

I am working with ForgeGradle (Minecraft Forge modding platform).
I'd like to obfuscate my mod before publishing but the nature of Forge platform won't allow me to do it by simply running program like ProGuard after compilation (with defined libraries).
Why?
The structure goes like this:
Mod -> Forge -> Minecraft
Since Minecraft uses its own obfuscated classes and ForgeGradle compilator is not DIRECTLY obfuscating Mod's code to fit with Minecraft's one, it is not possible to use MC.jar as library while using ProGuard. Compiled Forge Mod is actually decoded by Forge in runtime using SRG names. The logic behind this is not easily explainable so I'll just note: I cannot obfuscate .jar in a way to fit with libraries.
So I though - I could just take my mod's code (.java files) and rename all fields/methods/classes that are MINE before Forge compilation.
Is there a software that would allow me to pick number of .java files and "obfuscate" them in a way to not reaname references that don't belong to them?
EDIT (more explanation):
Mod's code has 3 states: Development, Compiled, Running.
I will try to give an example:
Let's say there is a decompiled method ItemSword.onHit() inside Minecraft.jar
And its compiled (obfuscated) version look like this: bca.aa(), also all packages are lost (flattened).
In mod's development state of code (.java) to make reference to it we simply make: ItemSword.onHit()
When we compile mod the call will look like this (.class): ItemSword.func_ab4234() - this is the SRG I was talking about.
Now when the mod will be loaded to game, forge will translate "ItemSword" to "bca" and "func_ab4234()" to "aa()"
Because of this I can't even add proper library - there IS NONE. I will always get (in ProGuard) NoClassDefFound Warning and I can't ignore it (it will crash compilation).
So after this edit - Is it still possible to make obfuscation with ProGuard (considering I cannot have "good" library assigned)?
Did you try the proguard options?
http://proguard.sourceforge.net/manual/usage.html
e.g. for Serializable classes and other stuff put this to your proguard configuration (you also can preserve complete classes if you like):
<!-- With this code serializable classes will be backward compatible -->
<keepnames implements="java.io.Serializable"/>
<!-- or for native access:-->
<keepclasseswithmembernames>
<method access="native"/>
</keepclasseswithmembernames>
<!--Preserve all public classes, and their public and protected fields and methods.-->
<keep access="public">
<field access="public protected"/>
<method access="public protected"/>
</keep>
If I got your question, you want to obfuscate your own code, not anything beyond that. That's what ProGuard is actually quite good at. Let's assume you created your classes in the packages com.foo and com.bar. You can use this simple ProGuard command to only obfuscate your own classes:
-keep class !com.foo.**,!com.bar.** { *; }
It tells ProGuard to not obfuscate any members of classes which do not belong to either com.foo or com.bar.
If you are getting NoClassDef errors, you added the wrong library. I guess you are using some kind of IDE (perhaps eclipse). Have a look at the libraries your project references to find the correct library classpath (e.g. a jar file). You basically need to find the classpath used for compiling your code, ProGuard will take that as well and everything should work.

Categories

Resources