Package contains object and package with same name - java

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.

Related

PsiClass to java.lang.Class

I'm developing plugin for IntelliJ IDEA. How can plugin get the name and version of libraries that are imported to the project that is being checked by plugin? I have PsiClass of the project, but cannot convert it to java.lang.Class. Maybe there's the way to get ClassLoader from PsiElement?
super.visitImportStatement(psiImport);
Class importedClass = Class.forName(psiImport.getQualifiedName(), true, psiImport.getClass().getClassLoader());
PsiImport.getClass().GetClassLoader() - returns ClassLoader of class PsiImportStatementImpl instead of ClassLoader of class that I've imported.
IntelliJ does mostly static analysis on your code. In fact, the IDE and the projects you run/debug have completely different classpaths. When you open a project, your dependencies are not added to the IDE classpath. Instead, the IDE will index the JARs, meaning it will automatically discover all the declarations (classes, methods, interfaces etc) and save them for later in a cache.
When you write code in your editor, the static analysis tool will leverage the contents of this index to validate your code and show errors when you're trying to use unknown definitions for example.
On the other hand, when you run a Main class from your project, it will spawn a new java process that has its own classpath. This classpath will likely contain every dependency declared in your module.
Knowing this, you should now understand why you can't "transform" a PsiClass to a corresponding Class.
Back to your original question:
How can plugin get the name and version of libraries that are imported to the project that is being checked by plugin?
You don't need to access Class objects for this. Instead, you can use IntelliJ SDK libraries. Here's an example:
Module mod = ModuleUtil.findModuleForFile(virtualFile,myProject);
ModuleRootManager.getInstance(mod).orderEntries().forEachLibrary(library -> {
// do your thing here with `library`
return true;
});

Failing to obfuscate Java code with ProGuard

I'm trying to optimize / obfuscate a java project with ProGuard.
I extract the project as a runnable jar from eclipse, and it runs just fine.
When I try to compress it with ProGuard, I get thousands of warning and errors, in particular at the end:
Note: there were 1 classes trying to access generic signatures using reflection.
You should consider keeping the signature attributes
(using '-keepattributes Signature').
Note: there were 14 unresolved dynamic references to classes or interfaces.
You should check if you need to specify additional program jars.
Note: there were 2 class casts of dynamically created class instances.
You might consider explicitly keeping the mentioned classes and/or
their implementations (using '-keep').
Note: there were 15 accesses to class members by means of introspection.
You should consider explicitly keeping the mentioned class members
(using '-keep' or '-keepclassmembers').
Warning: there were 13229 unresolved references to classes or interfaces.
You may need to add missing library jars or update their versions.
If your code works fine without the missing classes, you can suppress
the warnings with '-dontwarn' options.
Warning: there were 61 instances of library classes depending on program classes.
You must avoid such dependencies, since the program classes will
be processed, while the library classes will remain unchanged.
Warning: there were 18 unresolved references to program class members.
Your input classes appear to be inconsistent.
You may need to recompile the code.
The external libs I used in the project are added to the jar upon exporting it from eclipse. ("Extract required libraries into jar"). I did not use the "repack into jar" option because it really slows jars down.
The libs in particular are:
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
Am I doing something fondamentally wrong here?
I have tried without success the suggestions of proguard, and my code compiles in eclipse with no warnings.
It's a very big project so I can't really provide an MCVE, but if someone could point me in the right direction here as to what I'm missing, I'd really appreciate it.
Example of the warning: (It goes on for every single method)
http://pastebin.com/m9hX9LJA
Obviously this might be too general of a problem for you guys to fix, however I might be doing some major obvious mistake that I'm not realizing, that's what I'm going for with this.
Notes are just suggestions, but warnings point out inconsistencies in the input. Notably, the 13229 unresolved references suggest that you are providing the main code of your application (with -injars), but not its libraries (with -injars or -libraryjars). I don't know of Eclipse's Extract or Repack options, but you should check the contents of your input jar(s).
See the ProGuard manual > Troubleshooting > Warning: can't find referenced class.

Module dependancies in IntelliJ12 not working for packages [duplicate]

I'm working now together with others in a grails project. I have to write some Java-classes. But I need access to an searchable object created with groovy. It seems, that this object has to be placed in the default-package.
My question is: Is there a way to access this object in the default-package from a Java-class in a named package?
You can’t use classes in the default package from a named package.
(Technically you can, as shown in Sharique Abdullah's answer through reflection API, but classes from the unnamed namespace are not in scope in an import declaration)
Prior to J2SE 1.4 you could import classes from the default package using a syntax like this:
import Unfinished;
That's no longer allowed. So to access a default package class from within a packaged class requires moving the default package class into a package of its own.
If you have access to the source generated by groovy, some post-processing is needed to move the file into a dedicated package and add this "package" directive at its beginning.
Update 2014: bug 6975015, for JDK7 and JDK8, describe an even stricter prohibition against import from unnamed package.
The TypeName must be the canonical name of a class type, interface type, enum type, or annotation type.
The type must be either a member of a named package, or a member of a type whose outermost lexically enclosing type is a member of a named package, or a compile-time error occurs.
Andreas points out in the comments:
"why is [the default package] there in the first place? design error?"
No, it's deliberate.
JLS 7.4.2. Unnamed Packages says: "Unnamed packages are provided by the Java SE platform principally for convenience when developing small or temporary applications or when just beginning development".
In fact, you can.
Using reflections API you can access any class so far. At least I was able to :)
Class fooClass = Class.forName("FooBar");
Method fooMethod = fooClass.getMethod("fooMethod", String.class);
String fooReturned = (String)fooMethod.invoke(fooClass.newInstance(), "I did it");
Use jarjar to repackage the jar file with the following rule:
rule * <target package name>.#1
All classes in the default package of the source jar file will move to the target package, thus are able to access.
You can use packages in the Groovy code, and things will work just fine.
It may mean a minor reorganization of code under grails-app and a little bit of a pain at first, but on a large grails project, it just make sense to organize things in packages. We use the Java standard package naming convention com.foo.<app>.<package>.
Having everything in the default package becomes a hindrance to integration, as you're finding.
Controllers seem to be the one Grails artifact (or artefact) that resists being put in a Java package. Probably I just haven't figured out the Convention for that yet. ;-)
just to complete the idea:
From inside default-package you can access objects resided in named packages.

com.sun.xml.internal.ws.client does not exist

I'm trying to catch ClientTransportException and my program fails on compilation stage with the following exception
[ERROR]\workspace\rates\java\service\bundle1\src\main\java\com\connector\ws\TestClass1.java:[72,70] package com.sun.xml.internal.ws.client does not exist
As I know this package is from rt.jar and exist in jre
If I add #SuppressWarnings("restriction") it compiles from Eclipse Maven Plugin, but not from IntelliJ Idea(via maven) or command line neither.
When I remove #SuppressWarnings Eclipse show the following warning
Access restriction: The type ClientTransportException is not accessible due to restriction on required library C:\Program Files\Java\jre6\lib\rt.jar
I've found similar question but it's answer isn't clear enough for me cause I can this class in rt.jar and my IntelliJ Idea can see it either.
Can someone explain such behavior and possible solution for it?
According to this FAQ it's a bad practice to directly call 'sun' packages. When I ran into the same problem it was fixed by catching javax.xml.ws.WebServiceException instead (as sugested by artbristol).
You can get rid of this error using :
javac -XDignore.symbol.file=true
That's the argument to pass to javac to use rt.jar instead of ct.sym (ct.sym is used by default and required for compiling to a target older version)
ct.symdoes not contains all classes from rt.jar. Because using sun.* classes should not be used the class stub for them might not be present in in ct.sym making the compilation fails.
Removing calls to sun.* should remove this issue. (It's a bad practice to use sun packages)
References :
https://blogs.oracle.com/geertjan/ctsym-steals-the-asm-class
The truth of the matter is that there's something called "ct.sym" in the JDK. When javac is compiling code, it doesn't link against rt.jar. Instead, it uses a special symbol file lib/ct.sym with class stubs. Internal JDK classes are not put in that symbol file, since those are internal classes. You shouldn't want to use them, at all.
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6778491
This is not a compiler issue. javac is behaving correctly, according to the information provided in ct.sym.
The issue belongs with those who decide what should be available with (and what should be hidden by) ct.sym
I cannot as yet determine the correct category for this bug.
This is intentional. Perhaps the package name "com.sun.xml.internal...." might be seen as a hint.
Users should not write code that depends on internal JDK implementation classes. Such classes are internal implementation details of the JDK and subject to change without notice.
http://openjdk.java.net/jeps/247
For JDK N and --release M, M < N, signature data of the documented APIs of release M of the platform is needed. This data is stored in the $JDK_ROOT/lib/ct.sym file, which is similar, but not the same, as the file of the same name in JDK 8. The ct.sym file is a ZIP file containing stripped-down class files corresponding to class files from the target platform versions.
For JDK N and --release N,the JDK's own image is used as the source of the class files to compile against. The list of observable modules is limited, however, to the documented modules and the jdk.unsupported module.
NOTE
In this case, it would be better to not use the ClientTransportException class and replaced it by javax.xml.ws.WebServiceException, as suggested by artbristol.
Jre System library restricts some packages access to compiler, while they are accessible to JDK. In that case there will be no error in code but when compiling it will show errors like class not found or package not found.
In that case there are two practices.
1) Add rt.jar of jre system library to your build path for compiling and building.
2) Add jaxws-rt.jar in your build path.
Second option is a good option as it will avoid adding duplicate libraries to your build path.
import this dependency in pom.xml
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.1.4</version>
</dependency>
Even in 2015, I've found many projects that use this bad practice of importing com.sun.* packages.
If you (like me) can't change the classes importing those packages, adding rt.jar to your classpath should do the trick.
Note that the said rt.jar is usually found under <jdk_home>/jre/lib folder.
The solution is quite simple: when you copy the ready-made code or write the code first and then load the dependencies, there is a dependency conflicts. com.sun.xml.* package is already part of JDK8, but Maven does not see it when compiling. So make sure that you use the package from mvn:repo:/...rt.jar not jdk* / .../rt.jar.
Even I was facing same issue in my maven project. I had imported
import com.sun.xml.internal.ws.client.ResponseContext; in one of class file but this was not in use.
I just commented the line in my class file and the error stopped and i could successful run my maven project.
For maven build adding the following plugin will resolve the issue.
Basically adding the compiler arguments to refer correct path of tools.jar
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArguments>
<bootclasspath>${java.home}/lib/rt.jar${path.separator}${java.home}/lib/jce.jar${path.separator}${java.home}/../lib/tools.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
You should not use com.sun.* packages.
We could solve the problem by using our own class instead:
/**
* Copy of com.sun.xml.internal.ws.client.BindingProviderProperties since we're
* not allowed to use com.sun.* packages..
*/
public final class BindingProviderProperties {
public static final java.lang.String CONNECT_TIMEOUT = "com.sun.xml.internal.ws.connect.timeout";
public static final java.lang.String REQUEST_TIMEOUT = "com.sun.xml.internal.ws.request.timeout";
}

How to change DSLD compile classpath in Eclipse

I'd like to do some import of my own classes for use inside DSLD script, but DSLD compilation does not seem to use project's classpath - import statements break the compilation, and Class.forName throws class not found exception.
Is there a way to put custom jars on DSLD classpath, so I can use my own classes inside conribution blocks?
I am using Eclipse 3.7 and latest groovy plugin (2.6.0)
You can just pass a string with the fully qualified class name and as long as its on the projects classpath where the DSLD is being evaluated then it will work. This is described here groovy-eclipse DSLDs
Some subtleties about java.lang.Class references
Even though the DSLD script is being edited in the context of your
project, the script is actually loaded by Groovy-Eclipse. And so, the
runtime classpath of the script corresponds to Groovy-Eclipse's
classpath, rather than the classpath of your project.
Consequently, you cannot reference class objects for types defined in
your project. However, you can reference class objects that are
available to Groovy-Eclipse. This might be confusing since the
compiler will not show compile errors when types defined in your
project are referenced as class objects, but it will show compile
errors when Groovy-Eclipse types are referenced. This is because the
Groovy-Eclipse compiler works off of the project's classpath. It is
not yet aware that DSLD files will be run with a different classpath.
More specifically:
Instead of referencing the class MyLocalType directly, you can
reference it as a String "com.mycompany.MyLocalType" Standard JDK,
GDK, and all types defined in groovy-all are available directly in
your DSLD and will show compile errors. It is possible to reference
types in packages beginning with org.eclipse.jdt. and
org.codehaus.groovy.eclipse. if all references are fully qualified.
However, this is not recommended unless you really know what you are
doing.
I don't know much about the DSLD stuff, but it looks like Groovy might have it's own means of doing that.

Categories

Resources