Force IntelliJ to Keep Same-Package Import Statements - java

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).

Related

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.

AspectJ 'thisJoinPoint' throws exception

I'm using AspectJ and the 'ajc' command line compiler. I specify aspectjrt.jar, aspectjtools.jar, and aspectjweaver.jar on the classpath ('-cp') during compilation, yet when I call the standard 'thisJoinPoint', an exception is thrown:
Compilation:
ajc -cp lib/aspectjrt.jar:lib/aspectjtools.jar:lib/aspectjweaver.jar -inpath work/src/ -outjar ./mynewjar.jar #work/source.lst
Code which causes exception:
before() : onCreateCall() {
System.out.println("[-] PC Info: " + thisJoinPoint.getSignature());
}
And the exception itself:
Could not find class 'org.aspectj.runtime.reflect.Factory', referenced from method com.test.WooAspects.ajc$preClinit
Of course, I've tried specifying the import with the following, but no luck:
import org.aspectj.runtime.reflect.Factory;
import org.aspectj.runtime.reflect.*;
Any ideas?
When compiling your code, if it references types in a separate library, that library (possibly packaged as a .jar) needs to be available on the compilation classpath (javac or ajc in this case).
When running your code, if it references types in a separate library, that library needs to be available on the runtime classpath (java or the alternative for aspectj).
Note that an import statement is unrelated to the classpath. All an import statement does is allow you to use a type's or member's short name instead of its fully qualified name.
The following things seem to be a little odd at first glance:
It looks as if you think that -inpath work/src actually is meant to include source files, but the inpath is actually meant to include class files. What you probably want is -sourceroots work/src.
Then you seem to use an argument file named work/source.lst which you have not shown us, so we do not know what is in there - maybe more command line switches, maybe more source files. I have no idea.
On your ajc classpath there are all three AspectJ libraries, but usually you only need aspetcjrt.jar. The other two are only needed for load-time weaving [LTW] (aspectjtools.jar) or if you want to use the AspectJ compiler and a few other tools during runtime (aspectjweaver.jar).
For a simple project in which Java and AspectJ code are in the same source directory, the following works for me (inserting line breaks for better readability, but it is all one line on the console):
ajc
-1.7
-cp lib/aspectjrt.jar
-sourceroots src
-outjar my.jar
Then you run the aspect-enhanced JAR like this (again one line on the console):
java
-cp lib/aspectjrt.jar;my.jar
de.scrum_master.app.Application
I.e. during runtime you also just need the runtime JAR on your classpath.
Maybe you want to use a build tool like Maven managing your dependencies and the build process. You can also use plugins like Maven Shade or One-JAR in order to produce a single über-JAR containing both the compiled Java + AspectJ code and the AspectJ runtime. Then you do not have any problems with classpaths during runtime, you just call
java -jar my_uber.jar
Update: You may want to read the ajc documentation for more info.

How are these classes able to access the default package (post-compile)?

This is taken from the bytecode of Minecraft. Most of the jar's classes are found in the default package, however there is another package, "net.minecraft.client", which has the main class (Minecraft.class) that runs the game loop, sets up OpenGL, etc. I don't have the source, but if I open up Minecraft.class in JD-Gui, it has the following import setup:
package net.minecraft.client;
import aaa;
import aai;
import ajq;
import ajv;
import akf;
import aki;
import aqx;
import aqz;
import ara;
import arb;
... (many more classes from the default package)
public abstract class Minecraft implements Runnable, mc {
...
}
How does this work? Let's say I have a folder with a similar setup (default classes that need to be accessed by other packages) and want to compile it with a batch file. What method of compiling could replicate this result?
This is taken from the source of Minecraft.
I don't think so. (EDIT: The question was edited to make this "bytecode" - which doesn't make much sense, as bytecode isn't Java source code. Anyway...)
How does this work?
It doesn't, fundamentally. The code you're looking at in JD-Gui isn't the original source code - it's code which represents the bytecode as accurately as JD-Gui is able to manage.
I strongly suspect the original source code does use packages, but then uses an obfuscator of some kind to rename the classes and put them in the default package. I strongly suspect this isn't the only kind of change which leaves valid bytecode which couldn't actually be directly compiled from valid source code. (For example, I strongly suspect there are method names which are valid in bytecode but not in source code.)
Let's say I have a folder with a similar setup (default classes that need to be accessed by other packages) and want to compile it with a batch file. What method of compiling could replicate this result?
You wouldn't. You'd have source code set up using packages (as all sane, non-trivial Java code does), compile it and then post-process the bytecode.

Package contains object and package with same name

I am having problems compiling some Scala with Maven or Eclipse where I try to import a class from a Java jar which contains both a namespace and class of the same name.
I can compile with scalac, however.
E.g. the Java project (jar) contains:
src/foo/bar.java
src/foo/bar/some_resource.txt
-> foobar.jar
Scala project references foobar.jar
Foobartest.scala:
import foo.bar
class foobartest {
}
The compiler complains with:
package foo contains object and package with same name: bar
one of them needs to be removed from classpath
Using Maven 3.0.03/Eclipse 3.7.1 with Scala 2.9.0.1 (and maven-scala-plugin).
The jar which I am having problems with is jenkins-core-1.399.jar - it definitely contains several instances where there is a namespace and object of the same name.
I am attempting to write a Jenkins plugin in Scala (I could do this in Java but would prefer scala since all of our libraries are in scala), which is dependent on using Maven -
https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial.
That kind of limitation was outlined in SI-4695: package object misbehaves in the presence of classfiles.
As suggested in SI-2089 (naming restriction makes some jars unusable), you could try and use the "resolve-term-conflict", as implemented in changeset 25145:
Added a -Y option to resolve namespace collisions between package and object.
It's a blunt instrument: if people have lots of these conflicts they need to resolve in individually nuanced fashion, they'll probably remain out of luck.
val termConflict = ChoiceSetting ("-Yresolve-term-conflict", "strategy", "Resolve term conflicts", 113 List("package", "object", "error"), "error")
// Some jars (often, obfuscated ones) include a package and
// object with the same name. Rather than render them unusable,
// offer a setting to resolve the conflict one way or the other.
// This was motivated by the desire to use YourKit probes, which
// require `yjp.jar` at runtime. See SI-2089.
The actual compiler option is "-Yresolve-term-conflict:strategy" where strategy is either package, object, error.

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

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!

Categories

Resources