Java 8: Spliterator, Iterator, Collection and "default" implemenations in Interfaces (Duplicate methods named spliterator) - interface

Have an interesting situation following the release of Java 1.8.0_25 into the wilds... I believe the root of my issue is related primarily to the new (to 1.8) features of "default" implementations within Interfaces.
The application I am working on is currently targeted at 1.7, which until now has been working well. Until users started updating to 1.8. Now that our users have started updating to 1.8, our hand is forced somewhat into moving to 1.8 support.
We have fixed most of the issues (mainly relating to changes to the JavaFX packages between 1.7 and 1.8) but have one vexing issue remaining.
In my wisdom, or lack thereof, I, some time ago, decided to create a SortedList<T> which extends from AbstractList<T>. Until now, this class has worked fine, however when running on a 1.8 runtime, I get:
Duplicate methods named spliterator with the parameters () and () are inherited
from the types Collection<T> and Iterable<T>
This, to me, appears to be caused by the "default" implementations in some of the Interfaces that are implemented by AbstractList<T> (my SortedList<T> class does not implement any additional Interfaces other than Serializable). Implementing Serializable is another problem for us, as we need to support deserialisation of SortedList<T> objects, there's no way around that!).
I can get rid of the error by providing an override implementation of spliterator() in my SortedList<T> class. However, if this is built, it no longer runs on a Java 1.7 environment. If I attempt to use SortedList<T> with a 1.7 runtime, I get:
Problem:
Error: Unresolved compilation problems:
The import java.util.Spliterator cannot be resolved
Spliterator cannot be resolved to a type
com.xxxx.xxxx.util.SortedList.<init>(SortedList.java:13)
This error is pretty obvious, since we've now overridden the spliterator() method in SortedList<T> it needs to include java.util.Spliterator, but that doesn't exist in 1.7.
Ideally we would like to NOT require our customers to update to Java 1.8 if they don't want to.
Is our hand being forced here? Do we need to force users to update to 1.8 and also roll out a new version to any users who have updated to 1.8 by themselves?
Does anyone know a way around this issue?
On a more philosophical note, why has Interface been corrupted with with implementation :-(. Might be a nifty new feature, but they really should have avoided doing anything that would result in breaking changes to existing code, particularly in something so fundamental as lists/collections etc.
Any help or suggestions regarding this predicament would be greatly appreciated.
Cheers,
Mark

The whole point of default methods is to avoid the situation you describe. The code below compiles and runs as expected with Java 7 and 8:
public class SortedList<T> extends AbstractList<T> implements Serializable {
#Override public T get(int index) { return null; }
#Override public int size() { return 0; }
public static void main(String[] args) {
SortedList<String> s = new SortedList<> ();
System.out.println(s.size());
}
}

Ok, so both of you (#Holger and #assylias) were correct... But, our situation is a little more complicated.
The environment we're working in is Eclipse 3.8.1 which doesn't support Java 8 (and won't in the future to my knowelege). So we can't just change to a Java 8
compiler to fix the issues.
Our product is a sizeable Eclipse RCP application. Upgrading our IDE is not currently an option, as there would be major rework involved. We will need to continue
to develop under a Java 1.7 environment for this reason.
If anyone is interested, we have resolved the issue by:
Creating fragments (one per Java version that causes issues, so three in our case) for our main plugin. These fragments are configured as patch fragments.
Added the Java FX JARs into the fragments (This was done to resolve some issues with Java FX in an earlier release and again for the 1.8.0_25 release).
Also in the fragments, in the same namespace as the main plugin, we added the implementation of the SortedList class. The code is identical for each case, but
the fragment for Java 8 is compiled specifically with a Java 8 compiler. Overriding the spliterator() method wasn't necessary in the end (when compiled with the Java 8
compiler, it works ok and still compiles with the 1.7 compiler as there is no reference to the Spliterator class anymore).
This is probably not an ideal solution, but it will work we think :-).
Thanks for your input & suggestions, much appreciated.

try Creating an abstract class that overrides the spliterator() with the prefered behaviour definition i.e.
abstract class Java8_AbstractCollection<E> extends AbstractCollection<E> {
/* (non-Javadoc)
* #see java.util.Collection#spliterator()
*/
public Spliterator<E> spliterator() {
return (Spliterator<E>) super.spliterator();
}
}

Related

scala error when extending java.util.Stack : error while loading vector$

I'm using scala v2.10.2; eclipse with scala plugin v3.0.1; The full error message is:
error while loading Vector$1, class file 'C:\Program
Files\Java\jre7\lib\rt.jar(java/util/Vector$1.class)' is broken (class
java.util.NoSuchElementException/key not found: E)
It occurs when attempting to extending java.util.Stack
import java.util.Stack
class MyStack[T] extends Stack[T]{}
It's worth noting that java.util.Stack is a subclass of java.util.Vector.
java.util.Stack extends the essentially deprecated java.util.Vector, and thus is also essentially deprecated (they're not actually deprecated, but the docs always recommends using newer alternatives if you're running a newer version of Java). The javadoc for Stack recommends using the java.util.Deque interface instead:
A more complete and consistent set of LIFO stack operations is provided by the Deque interface and its implementations, which should be used in preference to this class. For example: Deque<Integer> stack = new ArrayDeque<Integer>();
Using the Deque interface and java.util.ArrayDeque will probably solve your problem since—referring to pretzels1337's answer—this seems to be a Vector-specific bug.
eThis same issue may be part of a larger bug report:
https://issues.scala-lang.org/browse/SI-7455
The report claims fixed in Scala 2.10.3-RC1, Scala 2.11.0-M6
I'm waiting for the next stable scala IDE update before verifying fixed (lazy I know) but a simple work around in the mean time is to simply change the class definitions to extend scala.collection.mutable.Stack instead.
--
Most people running into this issue are trying to use swing; for you I can only recommend trying one of the fixed builds of scala.

TrueZip 7 requires Java 7? NoClassDefFoundError: java/nio/file/Path on Java 6

TFile depends on java.nio.file.Path (toPath() method returns java.nio.file.Path) that isn't available on Java 6 so calling any TFile method on Java 6 throws "java.lang.NoClassDefFoundError: java/nio/file/Path"
How do you manage to use TFile on Java 6? What I'm thinking of is getting the sources, re-compiling them without this method and using a patched version which is kind of unpleasant solution.
No, TrueZIP 7 does not require JSE 7, JSE 6 is enough as the home page documents. However, some features are only available on JSE 7 (e.g. the TrueZIP Path module) and hence a run time test is performed.
With correct class loader implementations you will never see NoClassDefFoundError. However, some environments have broken class loader implementations which do eager class loading - despite the lazy class loading which is mandated by the spec. Only then you would get a NoClassDefFoundError.
On another note, please mind the Eclipse license of the project. If you really wanted to fix this by patching (you can't because there are circular dependencies between java.io.File and java.nio.file.Path which are the reason for this design), then you would have to publish this fork.
Appendix:
The Java Language Specification for Java 6, chapter 12.2.1 "The Loading Process" reads:
Different subclasses of ClassLoader may implement different loading policies. In particular, a class loader may cache binary representations of classes and interfaces, prefetch them based on expected usage, or load a group of related classes together. These activities may not be completely transparent to a running application if, for example, a newly compiled version of a class is not found because an older version is cached by a class loader. It is the responsibility of a class loader, however, to reflect loading errors only at points in the program where they could have arisen without prefetching or group loading.
English isn't my mother tongue, but I take it from the last sentence that eager class loading is OK as long as the class loader doesn't throw up just because an unused class failed to load eagerly. So if a class loader throws up because TFile.toPath() needs to return a java.nio.file.Path although you never call this method then I consider this to be a problem with the class loader. As an aside, TFile.toPath() throws an UnsupportedOperationException - please check the Javadoc for details.
I would have preferred to take another route but the circular dependency between java.io.File.toPath() and java.nio.file.Path.toFile() left me with no choice.

Drools - Changing the Java compiler level

I want to change the java compiler level to 1.6 but it doesn't seem to work for me. I am trying to use generics in the consequence part.
Following is my code that I used to change the compiler level.
Drools Version: 5.2.1 GA
*JDK Version : 1.6*
final Properties properties = new Properties();
properties.setProperty("drools.dialect.java.compiler", "JANINO");
properties.setProperty("drools.dialect.default", "java");
properties.setProperty("drools.compiler.lnglevel", "1.6");
PackageBuilderConfiguration packageBuilderConfiguration =
new PackageBuilderConfiguration(properties,(ClassLoader[]) null);
final KnowledgeBuilder knowledgeBuilder = KnowledgeBuilderFactory
.newKnowledgeBuilder(packageBuilderConfiguration);
Let me know where I am going wrong.
Thanks for the help.
Janino intentionally does not support generics. It appears to be a conscious decision, so there's not likely to be a change in that with new versions. They're also not going to support the enhanced for() loop and enums, both of which I've also grown to miss in Drools.
Check out the Janino webpage, near the bottom right in what they do not support.
If you take out the "JANINO" line from your example, I'd be curious if you could start using them. (The default compiler is the eclipse compiler, at least it was the last time I checked.

Why am I getting NullPointerException in the CompilationUnit instances returned from ASTParser.createASTs()

I am working on an Eclipse JDT plugin that requires parsing large numbers of source files,
so I am hoping to use the batch method ASTParser.createASTs(). The parsing executes without errors, but within the CompilationUnit instances it produces, many of the org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding instances have had their scope field set to null. This setting to null is occurring in the CompilationUnitDeclaration.cleanUp() methods, which are invoked on a worker thread that is unrelated to my plugin's code (i.e., my plugin's classes do not appear on the cleanUp() method call stack).
My parsing code looks like this (all rawSources are within the same project):
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setResolveBindings(true);
parser.setStatementsRecovery(true);
parser.setBindingsRecovery(true);
parser.setIgnoreMethodBodies(false);
parser.setProject(project);
parser.createASTs(rawSources.values().toArray(new ICompilationUnit[0]), new String[0], this, deltaAnalyzer.progressMonitor);
Alternatively, I can execute the parsing this way, and no such problems occur:
for (ICompilationUnit source : rawSources.values())
{
parser.setResolveBindings(true);
parser.setStatementsRecovery(true);
parser.setBindingsRecovery(true);
parser.setIgnoreMethodBodies(false);
parser.setProject(project);
parser.setSource(source);
CompilationUnit ast = (CompilationUnit)parser.createAST(deltaAnalyzer.progressMonitor);
parsedSources.add(deltaAnalyzer.createParsedSource(source, ast));
}
This issue occurs in both Helios and Indigo (the very latest release build). I filed a bug in Eclipse Bugzilla, but if anyone knows of a way to work around this--or if I am using the API wrong--I would greatly appreciate your help.
Byron
Without knowing exactly what your exception is, I can still offer 2 suggestions:
Have a look at org.eclipse.jdt.ui.SharedASTProvider. If you are not making any changes to ASTs, this class may provide a more robust way of getting the ASTs.
Play around with some of the settings that you are using. Do you really need bindingsRecovery set to true? What about statementRecovery? Setting these to false may help you.

JNI signatures for nested classes?

I'm trying to use JNI on WindowsXP, java version:
java version "1.6.0_13"
Java(TM) SE Runtime Environment (build 1.6.0_13-b03)
Java HotSpot(TM) Client VM (build 11.3-b02, mixed mode, sharing)
When trying to get jclass for a nested class
jclass c = env->FindClass ("A$B");
assert (c);
the second line asserts, The same thing works ok on Linux with slightly different version of Java (1.5... IIRC).
I've tried several permutations like
LA$B;
A.B
LA.B;
but to no avail.
Any advice will be highly appreciated.
Martin
OK, I had a similar experience on Native Android, env->FindClass() would not find a nested class with A$B syntax. I moved stuff around and it wouldn't find even a non-nested class.
What turned out to be the issue is that Java->C++ JNI call can find classes, but if you have pure C++ thread, with jvm->GetEnv / jvm->AttachCurrentThread, this thread can do JNI stuff but not FindClass for some reason.
So my suggestion is if you hit weird FindClass behavior on Android, try to move it to a Java stack (i.e Java calling native method), it might help. Note that you might need NewGlobalRef for the jclass esp if it would be used later from another thread.
P.S. A$B is the correct way to refer to nested classes.
Seems like the issue was resolved in this thread.
Update: Oracle moved the the forums, the new location is Signature for nested class?
Here's how the issue was resolved:
Ok, I've finally found the problem. The nested class is compiled into a separate java class object (A$B.class) - a bit unexpecte for C/C++ programmer. I haven't packeged the file thus the class was reported as 'not found'. Interesting it worked on Linux though. Thanks for your help!
Another hint from me: In case FindClass returns null don't just assert and guess. At the very least call env->ExceptionDescribe() to get a stacktrace on stderr. Better still, use env->ExceptionOccurred() to check for the Java exception being thrown, just like you would on any other Java method you call.