Skip to content

Commit

Permalink
Fix StackOverflowError on resolving recursive types by collapsing cha…
Browse files Browse the repository at this point in the history
…ins of type bounds (#1075)

* Fixes StackOverflowError on resolving recursive types.

See Issue JodaOrg#440, Issue JodaOrg#603, tests.

* fix 'codacy' coding style warnings

* added copyright header
  • Loading branch information
amogilev authored and inder123 committed May 31, 2017
1 parent 5848096 commit a300148
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 2 deletions.
16 changes: 14 additions & 2 deletions gson/src/main/java/com/google/gson/internal/$Gson$Types.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,13 @@ public static GenericArrayType arrayOf(Type componentType) {
* this returns {@code ?}, which is shorthand for {@code ? extends Object}.
*/
public static WildcardType subtypeOf(Type bound) {
return new WildcardTypeImpl(new Type[] { bound }, EMPTY_TYPE_ARRAY);
Type[] upperBounds;
if (bound instanceof WildcardType) {
upperBounds = ((WildcardType) bound).getUpperBounds();
} else {
upperBounds = new Type[] { bound };
}
return new WildcardTypeImpl(upperBounds, EMPTY_TYPE_ARRAY);
}

/**
Expand All @@ -84,7 +90,13 @@ public static WildcardType subtypeOf(Type bound) {
* super String}.
*/
public static WildcardType supertypeOf(Type bound) {
return new WildcardTypeImpl(new Type[] { Object.class }, new Type[] { bound });
Type[] lowerBounds;
if (bound instanceof WildcardType) {
lowerBounds = ((WildcardType) bound).getLowerBounds();
} else {
lowerBounds = new Type[] { bound };
}
return new WildcardTypeImpl(new Type[] { Object.class }, lowerBounds);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (C) 2017 Gson Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.gson.internal.bind;

import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.internal.$Gson$Types;
import junit.framework.TestCase;

import java.io.PrintStream;
import java.lang.ref.WeakReference;

/**
* Test fixes for infinite recursion on {@link $Gson$Types#resolve(java.lang.reflect.Type, Class,
* java.lang.reflect.Type)}, described at <a href="https://github.com/google/gson/issues/440">Issue #440</a>
* and similar issues.
* <p>
* These tests originally caused {@link StackOverflowError} because of infinite recursion on attempts to
* resolve generics on types, with an intermediate types like 'Foo2&lt;? extends ? super ? extends ... ? extends A&gt;'
*/
public class RecursiveTypesResolveTest extends TestCase {

private static class Foo1<A> {
public Foo2<? extends A> foo2;
}

private static class Foo2<B> {
public Foo1<? super B> foo1;
}

/**
* Test simplest case of recursion.
*/
public void testRecursiveResolveSimple() {
TypeAdapter<Foo1> adapter = new Gson().getAdapter(Foo1.class);
assertNotNull(adapter);
}

//
// Real-world samples, found in Issues #603 and #440.
//
public void testIssue603PrintStream() {
TypeAdapter<PrintStream> adapter = new Gson().getAdapter(PrintStream.class);
assertNotNull(adapter);
}

public void testIssue440WeakReference() throws Exception {
TypeAdapter<WeakReference> adapter = new Gson().getAdapter(WeakReference.class);
assertNotNull(adapter);
}

//
// Tests belows check the behaviour of the methods changed for the fix
//

public void testDoubleSupertype() {
assertEquals($Gson$Types.supertypeOf(Number.class),
$Gson$Types.supertypeOf($Gson$Types.supertypeOf(Number.class)));
}

public void testDoubleSubtype() {
assertEquals($Gson$Types.subtypeOf(Number.class),
$Gson$Types.subtypeOf($Gson$Types.subtypeOf(Number.class)));
}

public void testSuperSubtype() {
assertEquals($Gson$Types.subtypeOf(Object.class),
$Gson$Types.supertypeOf($Gson$Types.subtypeOf(Number.class)));
}

public void testSubSupertype() {
assertEquals($Gson$Types.subtypeOf(Object.class),
$Gson$Types.subtypeOf($Gson$Types.supertypeOf(Number.class)));
}
}

0 comments on commit a300148

Please sign in to comment.