Skip to content

Commit

Permalink
fix toString() implementation in ParameterizedTypeImpl, add missing t…
Browse files Browse the repository at this point in the history
…oString() to WildcardTypeImpl
  • Loading branch information
JHahnHRO committed Aug 16, 2024
1 parent 0650a91 commit c53bc10
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.lang.reflect.Type;
import java.util.List;
import java.util.Objects;
import java.util.StringJoiner;

public record ParameterizedTypeImpl(Class<?> rawType, Type ownerType, List<Type> actualTypeArguments)
implements ParameterizedType, Serializable {
Expand Down Expand Up @@ -64,17 +65,15 @@ public boolean equals(Object obj) {
public String toString() {
StringBuilder sb = new StringBuilder();
if (ownerType != null) {
sb.append(ownerType).append("$");
sb.append(ownerType.getTypeName()).append("$").append(rawType.getSimpleName());
} else {
sb.append(rawType.getTypeName());
}
sb.append(rawType);
if (!actualTypeArguments.isEmpty()) {
sb.append("<");
for (Type actualType : actualTypeArguments) {
sb.append(actualType);
sb.append(",");
}
sb.deleteCharAt(sb.length() - 1);
sb.append(">");
StringJoiner sj = new StringJoiner(", ", "<", ">");
sj.setEmptyValue("");
actualTypeArguments.stream().map(Type::getTypeName).forEach(sj::add);
sb.append(sj);
}
return sb.toString();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package io.github.jhahnhro.enhancedcdi.types;

import java.io.Serializable;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.Arrays;
import java.util.List;
import java.util.StringJoiner;

public record WildcardTypeImpl(List<Type> upperBounds, List<Type> lowerBounds) implements WildcardType, Serializable {

public static final WildcardTypeImpl UNBOUNDED = new WildcardTypeImpl(List.of(), List.of());

public WildcardTypeImpl {
upperBounds = List.copyOf(upperBounds);
lowerBounds = List.copyOf(lowerBounds);
Expand Down Expand Up @@ -52,4 +54,29 @@ public int hashCode() {
// List.hashCode happens to give the same result as Arrays.hashCode that the JDK uses.
return lowerBounds.hashCode() ^ upperBounds.hashCode();
}

public String toString() {
StringBuilder sb = new StringBuilder();

List<Type> bounds;
if (lowerBounds.isEmpty()) {
if (!upperBounds.isEmpty() && !upperBounds.getFirst().equals(Object.class)) {
bounds = upperBounds;
sb.append("? extends ");
} else {
return "?";
}
} else {
bounds = lowerBounds;
sb.append("? super ");
}

StringJoiner sj = new StringJoiner(" & ");
for (Type bound : bounds) {
sj.add(bound.getTypeName());
}
sb.append(sj);

return sb.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,13 @@ void testHashCode(GenericArrayType jdkType) {

assertThat(myType).hasSameHashCodeAs(jdkType);
}

@ParameterizedTest
@MethodSource("io.github.jhahnhro.enhancedcdi.types.GenericArrayTypeImplTest#parametrizedTypes")
void testToString(GenericArrayType jdkType) {
final var myType = new GenericArrayTypeImpl(jdkType.getGenericComponentType());

assertThat(myType).hasToString(jdkType.toString());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.github.jhahnhro.enhancedcdi.types;

class OuterClass<T> {

static class StaticInnerClass<U> {}

class InnerClass<V> {}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,91 @@
package io.github.jhahnhro.enhancedcdi.types;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.params.provider.Arguments.arguments;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import jakarta.enterprise.util.TypeLiteral;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

class ParameterizedTypeImplTest {

static <T> Stream<Arguments> parametrizedTypes() {
return Stream.of(arguments(new TypeLiteral<List<String>>() {}.getType()),
arguments(new TypeLiteral<List<List<Integer>>>() {}.getType()),
arguments(new TypeLiteral<List<?>>() {}.getType()),
arguments(new TypeLiteral<List<T>>() {}.getType()),
arguments(new TypeLiteral<Map<String, Integer>>() {}.getType()),
arguments(new TypeLiteral<Map.Entry<String, Integer>>() {}.getType()),
arguments(new TypeLiteral<OuterClass.StaticInnerClass<String>>() {}.getType()),
arguments(new TypeLiteral<OuterClass<String>.InnerClass<Integer>>() {}.getType()));
}

@Nested
class TestConstructor {
@Test
void givenStaticInnerClass_whenCtorWithoutOwnerType_throwIAE() {
assertThatIllegalArgumentException().isThrownBy(
() -> new ParameterizedTypeImpl(OuterClass.StaticInnerClass.class, null, Integer.class));
}

@Test
void givenNonStaticInnerClass_whenCtorWithoutOwnerType_throwIAE() {
assertThatIllegalArgumentException().isThrownBy(
() -> new ParameterizedTypeImpl(OuterClass.InnerClass.class, null, Integer.class));
}

@Test
void givenTopLevelClass_whenCtorWithOwnerType_throwIAE() {
assertThatIllegalArgumentException().isThrownBy(
() -> new ParameterizedTypeImpl(List.class, OuterClass.class, Integer.class));
}

@Test
void givenWrongNumberOfTypeArguments_whenCtor_thenThrowIAE() {
assertThatIllegalArgumentException().isThrownBy(() -> new ParameterizedTypeImpl(Map.class, null));
assertThatIllegalArgumentException().isThrownBy(
() -> new ParameterizedTypeImpl(Map.class, null, Integer.class));
assertThatIllegalArgumentException().isThrownBy(
() -> new ParameterizedTypeImpl(Map.class, null, Integer.class, Integer.class, Integer.class));
}

@Test
void givenTypeArgumentsNullList_throwNPE() {
assertThatNullPointerException().isThrownBy(
() -> new ParameterizedTypeImpl(List.class, null, (List<Type>) null));
}

@Test
void givenTypeArgumentsNullArray_throwNPE() {
assertThatNullPointerException().isThrownBy(
() -> new ParameterizedTypeImpl(List.class, null, (Type[]) null));
}

@Test
void givenTypeArgumentsVarArgsContainNull_throwNPE() {
assertThatNullPointerException().isThrownBy(
() -> new ParameterizedTypeImpl(Map.class, null, Integer.class, null));
}

@Test
void givenTypeArgumentsContainNull_throwNPE() {
List<Type> types = new ArrayList<>();
types.add(null);

assertThatNullPointerException().isThrownBy(() -> new ParameterizedTypeImpl(List.class, null, types));
}
}

@Nested
class ConsistencyWithJDK {
@ParameterizedTest
Expand All @@ -35,14 +106,14 @@ void testHashCode(ParameterizedType jdkType) {

assertThat(myType).hasSameHashCodeAs(jdkType);
}
}

static <T> Stream<Arguments> parametrizedTypes() {
return Stream.of(Arguments.of(new TypeLiteral<List<String>>() {}.getType()),
Arguments.of(new TypeLiteral<List<List<Integer>>>() {}.getType()),
Arguments.of(new TypeLiteral<List<?>>() {}.getType()),
Arguments.of(new TypeLiteral<List<T>>() {}.getType()),
Arguments.of(new TypeLiteral<Map<String, Integer>>() {}.getType()),
Arguments.of(new TypeLiteral<Map.Entry<String, Integer>>() {}.getType()));
@ParameterizedTest
@MethodSource("io.github.jhahnhro.enhancedcdi.types.ParameterizedTypeImplTest#parametrizedTypes")
void testToString(ParameterizedType jdkType) {
final var myType = new ParameterizedTypeImpl((Class<?>) jdkType.getRawType(), jdkType.getOwnerType(),
jdkType.getActualTypeArguments());

assertThat(myType).hasToString(jdkType.toString());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,15 @@ void testEquals(WildcardType jdkType) {
void testHashCode(WildcardType jdkType) {
final var myType = new WildcardTypeImpl(jdkType.getUpperBounds(), jdkType.getLowerBounds());

assertThat(myType.hashCode()).isEqualTo(jdkType.hashCode());
assertThat(myType).hasSameHashCodeAs(jdkType);
}

@ParameterizedTest
@MethodSource("io.github.jhahnhro.enhancedcdi.types.WildcardTypeImplTest#parametrizedTypes")
void testToString(WildcardType jdkType) {
final var myType = new WildcardTypeImpl(jdkType.getUpperBounds(), jdkType.getLowerBounds());

assertThat(myType).hasToString(jdkType.toString());
}

@Test
Expand Down

0 comments on commit c53bc10

Please sign in to comment.