Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UnmodifiableCollection causes UnsupportedOperationException in MethodSimulator #65

Closed
darylteo opened this issue Jul 11, 2016 · 9 comments

Comments

@darylteo
Copy link

darylteo commented Jul 11, 2016

@sdaschner really bad one for me. I don't know why it doesn't like the code I'm writing, and I need this to work. :'(

Exception in thread "main" java.lang.UnsupportedOperationException
        at java.util.Collections$UnmodifiableCollection.add(Collections.java:1055)
        at com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.simulation.MethodSimulator.simulate(MethodSimulator.java:112)
        at java.util.LinkedList$LLSpliterator.forEachRemaining(LinkedList.java:1235)
        at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
        at com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.simulation.MethodSimulator.simulateInternal(MethodSimulator.java:75)
        at com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.simulation.InjectableArgumentMethodSimulator.simulate(InjectableArgumentMethodSimulator.java:63)
        at com.sebastian_daschner.jaxrs_analyzer.model.methods.ProjectMethod.invoke(ProjectMethod.java:47)
        at com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.simulation.MethodSimulator.simulateInvoke(MethodSimulator.java:183)
        at com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.simulation.MethodSimulator.simulate(MethodSimulator.java:95)
        at java.util.LinkedList$LLSpliterator.forEachRemaining(LinkedList.java:1235)
        at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
        at com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.simulation.MethodSimulator.simulateInternal(MethodSimulator.java:75)
        at com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.simulation.InjectableArgumentMethodSimulator.simulate(InjectableArgumentMethodSimulator.java:63)
        at com.sebastian_daschner.jaxrs_analyzer.model.methods.ProjectMethod.invoke(ProjectMethod.java:47)
        at com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.simulation.MethodSimulator.simulateInvoke(MethodSimulator.java:183)
        at com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.simulation.MethodSimulator.simulate(MethodSimulator.java:95)
        at java.util.LinkedList$LLSpliterator.forEachRemaining(LinkedList.java:1235)
        at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
        at com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.simulation.MethodSimulator.simulateInternal(MethodSimulator.java:75)
        at com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.simulation.MethodSimulator.simulate(MethodSimulator.java:60)
        at com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.ResourceMethodContentAnalyzer.analyze(ResourceMethodContentAnalyzer.java:63)
        at com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.BytecodeAnalyzer.analyzeBytecode(BytecodeAnalyzer.java:26)
        at java.lang.Iterable.forEach(Iterable.java:75)
        at java.util.Collections$UnmodifiableCollection.forEach(Collections.java:1080)
        at com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.BytecodeAnalyzer.analyzeBytecode(BytecodeAnalyzer.java:18)
        at com.sebastian_daschner.jaxrs_analyzer.analysis.ProjectAnalyzer.analyze(ProjectAnalyzer.java:100)
        at com.sebastian_daschner.jaxrs_analyzer.JAXRSAnalyzer.analyze(JAXRSAnalyzer.java:64)
        at com.sebastian_daschner.jaxrs_analyzer.Main.main(Main.java:97)
> gradle -version
Gradle 2.12
------------------------------------------------------------

Build time:   2016-03-14 08:32:03 UTC
Build number: none
Revision:     b29fbb64ad6b068cb3f05f7e40dc670472129bc0

Groovy:       2.4.4
Ant:          Apache Ant(TM) version 1.9.3 compiled on December 23 2013
JVM:          1.8.0_92 (Oracle Corporation 25.92-b14)
OS:           Mac OS X 10.11.5 x86_64

> java -version
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)

I can't really see this being a problem with Lombok. Could be Hibernate.

@darylteo
Copy link
Author

darylteo commented Jul 11, 2016

Some more info after more trial and error:

    @SuppressWarnings("unchecked")
    public List<Subscription> findAll(final Integer userId, final Integer type, final String code) {
        Criteria c = currentSession()
            .createCriteria(FollowingEntity.class)
            .add(Restrictions.eq("userId", userId));

        System.out.println(type);
        System.out.println(code);

        if (type != null) {
            c.add(Restrictions.eq("type", type));
        } else {
            c.add(Restrictions.ne("type", 0));
        }

        if (code != null) {
            c.createCriteria("company")
                .add(Restrictions.eq("stockCode", code));
        }

        return ((List<FollowingEntity>) c.list())
            .stream()
            .map(Subscription::new)
            .collect(Collectors.toList());
    }

This has the exception. Change the first if statement block to the following

c.add(Restrictions.eq("type", 1)); // works fine
c.add(Restrictions.eq("type", type.intValue())); // nope
c.add(Restrictions.eq("type", (int)type.intValue())); nope
c.add(Restrictions.eq("type", null)); // works fine
c.add(Restrictions.eq("type", "0")); // works fine
c.add(Restrictions.eq("type", type.toString())); // nope

This works

        if (type != null) {
            if (type == 1) {
                c.add(Restrictions.ne("type", 1));
            } else if (type == 2) {
                c.add(Restrictions.ne("type", 2));
            }
        }

Avoiding the unbox of Integer, and using int throughout the code does not have this issue either.

@darylteo
Copy link
Author

Perhaps the problem is here instead.

Hibernate Source

@darylteo
Copy link
Author

For the time being, I am making UnmodifiableElement return new HashSets instead of Collections.unmodifiableSet. Unsure of what the side effects may be, but for the time being I just need the spec to be generated.

@sdaschner
Copy link
Owner

Unfortunately I can't reproduce the error... Could you please provide more in that example, including imports and hibernate deps?

Or alternatively edit the systemtest project.

@darylteo
Copy link
Author

Will try. Like I said, it may have something to do with Hibernate's handling of unboxing integers / ints.

darylteo pushed a commit to darylteo/jaxrs-analyzer that referenced this issue Jul 24, 2016
The root cause of the exception stems from the usage of null constants
being passed into methods. The arguments are treated as Object then
in the bytecode are converted to their required concrete types through
the Load instruction, which leads to the UnsupportedOperationException
thrown by the UnmodifiableCollection.
@darylteo
Copy link
Author

darylteo commented Jul 24, 2016

@sdaschner please see the branch diff i have posted for reproduction of the error I have experienced. Problem not with Hibernate, but with "null" arguments to methods.

After a bit more debugging, the UnmodifiableElement seems to be pushed from a SizeChange instruction in simulateSizeChange (MethodSimulator.java:245). I wish I knew more about the bytecode instruction set, but I think this is about as far as I can diagnose.

Like I said, my hack right now is to simply make UnmodifableElement return a clone rather than a UnmodifiableCollection.

@darylteo
Copy link
Author

Just to provide as much info as I can, here's the expressions I managed to extract when the error occurs in the test project.

List of Instructions - the LOAD instruction is where error occurs.

instructions = {java.util.LinkedList@2452}  size = 5
 0 = {com.sebastian_daschner.jaxrs_analyzer.model.instructions.NewInstruction@2487} "NewInstruction{className='com/sebastian_daschner/jaxrs_test/Model'}"
 1 = {com.sebastian_daschner.jaxrs_analyzer.model.instructions.DupInstruction@2488} "DupInstruction{}"
 2 = {com.sebastian_daschner.jaxrs_analyzer.model.instructions.LoadInstruction@2489} "LoadStoreInstruction{type='LOAD', number=1', variableType=Ljava/lang/String;', name=id}"
 3 = {com.sebastian_daschner.jaxrs_analyzer.model.instructions.InvokeInstruction@2490} "InvokeInstruction{identifier=MethodIdentifier{containingClass='com/sebastian_daschner/jaxrs_test/Model', methodName='<init>', returnType='V', staticMethod=false, signature='(Ljava/lang/String;)V', parameters=1}}"
 4 = {com.sebastian_daschner.jaxrs_analyzer.model.instructions.ReturnInstruction@2491} "ReturnInstruction{}"

Relevant Instance Variables

runtimeStack = {java.util.Stack@2459}  size = 3
 0 = {com.sebastian_daschner.jaxrs_analyzer.model.elements.Element@2571} "Element{possibleValues=[], types='[Lcom/sebastian_daschner/jaxrs_test/Model;]'}"
 1 = {com.sebastian_daschner.jaxrs_analyzer.model.elements.Element@2571} "Element{possibleValues=[], types='[Lcom/sebastian_daschner/jaxrs_test/Model;]'}"
 2 = {com.sebastian_daschner.jaxrs_analyzer.model.elements.Element$UnmodifiableElement@2510} "Element{possibleValues=[], types='[Ljava/lang/Object;]'}"
localVariables = {java.util.HashMap@2460}  size = 1
 0 = {java.util.HashMap$Node@2508} "1" -> "Element{possibleValues=[], types='[Ljava/lang/Object;]'}"

darylteo pushed a commit to darylteo/jaxrs-analyzer that referenced this issue Jul 24, 2016
The root cause of the exception stems from the usage of null constants
being passed into methods. The arguments are treated as Object then
in the bytecode are converted to their required concrete types through
the Load instruction, which leads to the UnsupportedOperationException
thrown by the UnmodifiableCollection.
@sdaschner
Copy link
Owner

Deployed in a new SNAPSHOT version.

@darylteo
Copy link
Author

darylteo commented Aug 6, 2016

Legend =)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants