Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8292755

Non-default method in interface leads to a stack overflow in JShell

    XMLWordPrintable

Details

    • b15
    • generic
    • generic

    Backports

      Description

        A DESCRIPTION OF THE PROBLEM :
        Run jshell with the enclosed sample files. You will get StackOverflowError

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        jshell --enable-preview JsonToken.java SerializeTest.java


        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        jshell should run and load the Java files
        ACTUAL -
        Exception in thread "main" java.lang.InternalError: Exception during analyze - java.lang.StackOverflowError
        at jdk.jshell/jdk.jshell.TaskFactory$AnalyzeTask.analyze(TaskFactory.java:415)
        at jdk.jshell/jdk.jshell.TaskFactory$AnalyzeTask.<init>(TaskFactory.java:406)
        at jdk.jshell/jdk.jshell.TaskFactory.lambda$analyze$1(TaskFactory.java:178)
        at jdk.jshell/jdk.jshell.TaskFactory.lambda$runTask$4(TaskFactory.java:213)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskPool.getTask(JavacTaskPool.java:193)
        at jdk.jshell/jdk.jshell.TaskFactory.runTask(TaskFactory.java:206)
        at jdk.jshell/jdk.jshell.TaskFactory.analyze(TaskFactory.java:175)
        at jdk.jshell/jdk.jshell.TaskFactory.analyze(TaskFactory.java:161)
        at jdk.jshell/jdk.jshell.Eval.compileAndLoad(Eval.java:1060)
        at jdk.jshell/jdk.jshell.Eval.declare(Eval.java:893)
        at jdk.jshell/jdk.jshell.Eval.eval(Eval.java:140)
        at jdk.jshell/jdk.jshell.JShell.eval(JShell.java:493)
        at jdk.jshell/jdk.internal.jshell.tool.JShellTool.processSource(JShellTool.java:3624)
        at jdk.jshell/jdk.internal.jshell.tool.JShellTool.processSourceCatchingReset(JShellTool.java:1348)
        at jdk.jshell/jdk.internal.jshell.tool.JShellTool.processInput(JShellTool.java:1246)
        at jdk.jshell/jdk.internal.jshell.tool.JShellTool.run(JShellTool.java:1217)
        at jdk.jshell/jdk.internal.jshell.tool.JShellTool.runFile(JShellTool.java:3105)
        at jdk.jshell/jdk.internal.jshell.tool.JShellTool.start(JShellTool.java:962)
        at jdk.jshell/jdk.internal.jshell.tool.JShellToolBuilder.start(JShellToolBuilder.java:261)
        at jdk.jshell/jdk.internal.jshell.tool.JShellToolProvider.main(JShellToolProvider.java:120)
        Caused by: java.lang.IllegalStateException: java.lang.StackOverflowError
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.analyze(JavacTaskImpl.java:383)
        at jdk.jshell/jdk.jshell.TaskFactory$AnalyzeTask.analyze(TaskFactory.java:412)
        ... 19 more
        Caused by: java.lang.StackOverflowError
        at jdk.compiler/com.sun.tools.javac.code.Type.equalsIgnoreMetadata(Type.java:513)
        at jdk.compiler/com.sun.tools.javac.code.Types.isSubtype(Types.java:1083)
        at jdk.compiler/com.sun.tools.javac.code.Types.isSubtype(Types.java:1077)
        at jdk.compiler/com.sun.tools.javac.code.Types.isSuperType(Types.java:1304)
        at jdk.compiler/com.sun.tools.javac.code.Types.isSubtype(Types.java:1086)


        ---------- BEGIN SOURCE ----------
        JsonToken.java

        public sealed interface JsonToken
        {
            record BeginArrayToken()
                    implements JsonToken {}

            record EndArrayToken()
                    implements JsonToken {}

            record BeginObjectToken()
                    implements JsonToken {}

            record EndObjectToken()
                    implements JsonToken {}

            record ObjectNameToken(String name)
                    implements JsonToken {}

            record ValueSeparatorToken()
                    implements JsonToken {}

            record StringToken(String value)
                    implements JsonToken {}

            record NumberToken(Number value)
                    implements JsonToken {}

            record BooleanToken(boolean value)
                    implements JsonToken {}

            record NullToken()
                    implements JsonToken {}
        }

        ======================

        SerializeTest.java

        import java.lang.reflect.InvocationTargetException;
        import java.lang.reflect.RecordComponent;
        import java.util.Collection;
        import java.util.Collections;
        import java.util.List;
        import java.util.Optional;
        import java.util.function.Function;
        import java.util.stream.Stream;

        public interface JsonSerializer
        {
            static JsonSerializer instance()
            {
                return new JsonSerializer() {};
            }

            default Stream<JsonToken> serialize(Object o)
            {
                return switch (o) {
                    case null -> Stream.of(new JsonToken.NullToken());
                    case String str -> Stream.of(new JsonToken.StringToken(str));
                    case Number n -> Stream.of(new JsonToken.NumberToken(n));
                    case Boolean b -> Stream.of(new JsonToken.BooleanToken(b));
                    case Enum<?> e -> Stream.of(new JsonToken.StringToken(e.name()));
                    case Optional<?> optional -> serialize(optional.orElse(null));
                    case Collection<?> collection -> serializeCollection(collection);
                    case Object ignore when o.getClass().isRecord() -> serializeRecord(o);
                    default -> throw new IllegalArgumentException(); // we don't support this type
                };
            }

            Stream<JsonToken> serializeCollection(Collection<?> collection)
            {
                Stream.Builder<Stream<JsonToken>> builder = Stream.builder();
                builder.accept(Stream.of(JsonToken.BeginArrayToken.INSTANCE));
                boolean first = true;
                for (Object value : collection) {
                    if (first) {
                        first = false;
                    }
                    else {
                        builder.add(Stream.of(JsonToken.ValueSeparatorToken.INSTANCE));
                    }
                    builder.accept(serialize(value));
                }
                builder.accept(Stream.of(JsonToken.EndArrayToken.INSTANCE));
                return builder.build().flatMap(Function.identity());
            }

            Stream<JsonToken> serializeRecord(Object record)
            {
                RecordComponent[] recordComponents = record.getRecordComponents();
                Stream.Builder<Stream<JsonToken>> builder = Stream.builder();
                builder.accept(Stream.of(JsonToken.BeginObjectToken.INSTANCE));
                boolean first = true;
                for (RecordComponent recordComponent : recordComponents) {
                    if (first) {
                        first = false;
                    }
                    else {
                        builder.accept(Stream.of(JsonToken.ValueSeparatorToken.INSTANCE));
                    }
                    builder.accept(Stream.of(new JsonToken.ObjectNameToken(recordComponent.getName())));
                    try {
                        Object o = recordComponent.getAccessor().invoke(record);
                        builder.accept(serialize(o));
                    }
                    catch (IllegalAccessException | InvocationTargetException e) {
                        throw new RuntimeException(e);
                    }
                }
                builder.accept(Stream.of(JsonToken.EndObjectToken.INSTANCE));
                return builder.build().flatMap(Function.identity());
            }
        }

        ---------- END SOURCE ----------

        FREQUENCY : always


        Attachments

          Issue Links

            Activity

              People

                jlahoda Jan Lahoda
                webbuggrp Webbug Group
                Votes:
                0 Vote for this issue
                Watchers:
                6 Start watching this issue

                Dates

                  Created:
                  Updated:
                  Resolved: