Martin Desruisseaux created SIS-193:
---------------------------------------

             Summary: Remove the workaround for ServiceLoader bug
                 Key: SIS-193
                 URL: https://issues.apache.org/jira/browse/SIS-193
             Project: Spatial Information Systems
          Issue Type: Task
          Components: Referencing
            Reporter: Martin Desruisseaux
            Priority: Minor


As of 1.8.0_31-b13, {{java.util.ServiceLoader}} does not support usage of a 
second {{Iterator}} in the middle of a previous iteration. The following Java 
code provides two simple tests with a {{ServiceLoader}} iterating over two 
elements.

{code:java}
import java.util.Iterator;
import java.util.ServiceLoader;

public class ServiceLoaderTest {
    public static class I1 extends ServiceLoaderTest {}  // A dummy provider.
    public static class I2 extends ServiceLoaderTest {}  // An other provider.

    public static void main(String[] args) {
        test1();
        test2();
    }

    private static void test1() {
        System.out.println();
        System.out.println("---- TEST 1 ----");
        ServiceLoader<ServiceLoaderTest> loader = 
ServiceLoader.load(ServiceLoaderTest.class);

        Iterator<ServiceLoaderTest> it1 = loader.iterator();
        System.out.println("it1.hasNext() = " + it1.hasNext());
        System.out.println("it1.next()    = " + it1.next());

        Iterator<ServiceLoaderTest> it2 = loader.iterator();
        System.out.println("it2.hasNext() = " + it2.hasNext());
        System.out.println("it2.next()    = " + it2.next());

        System.out.println("it1.hasNext() = " + it1.hasNext());
        System.out.println("it1.next()    = " + it1.next());

        System.out.println("it2.hasNext() = " + it2.hasNext());  // Expected 
"true" here, but get "false".
    }

    private static void test2() {
        System.out.println();
        System.out.println("---- TEST 2 ----");
        ServiceLoader<ServiceLoaderTest> loader = 
ServiceLoader.load(ServiceLoaderTest.class);

        Iterator<ServiceLoaderTest> it1 = loader.iterator();
        System.out.println("it1.hasNext() = " + it1.hasNext());
        System.out.println("it1.next()    = " + it1.next());

        Iterator<ServiceLoaderTest> it2 = loader.iterator();
        System.out.println("it1.hasNext() = " + it1.hasNext());
        System.out.println("it2.hasNext() = " + it2.hasNext());
        System.out.println("it1.next()    = " + it1.next());
        System.out.println("it2.next()    = " + it2.next());  // 
ConcurrentModificationException here.
    }
}
{code}

The second test throws the following exception:

{noformat}
    Exception in thread "main" java.util.ConcurrentModificationException
        at 
java.util.LinkedHashMap$LinkedHashIterator.nextNode(LinkedHashMap.java:711)
        at 
java.util.LinkedHashMap$LinkedEntryIterator.next(LinkedHashMap.java:744)
        at 
java.util.LinkedHashMap$LinkedEntryIterator.next(LinkedHashMap.java:742)
        at java.util.ServiceLoader$1.next(ServiceLoader.java:479)
        at test.ServiceLoaderTest.test2(ServiceLoaderTest.java:47)
        at test.ServiceLoaderTest.main(ServiceLoaderTest.java:12)
{noformat}

The workaround applied in Apache SIS has been to add a {{LazySet}} internal 
class which wraps an {{Iterable}} and caches its values. But this is a little 
bit unfortunate since {{ServiceLoader}} already caches its values.

{{ServiceLoader}} is probably going to be significantly rewritten in JDK9 as a 
side effect of the Jigsaw project. So we should revisit if our {{LazySet}} 
workaround is still needed on a JDK9 branch.




--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to