Skip to content

Commit

Permalink
Merge pull request #49 from timothyjward/tests
Browse files Browse the repository at this point in the history
[generics] Restore deleted tests and improve consistency of access
  • Loading branch information
juergen-albert authored Sep 23, 2024
2 parents 685c07f + 91d582b commit 62de133
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ private static String generateGenericClassSignature(Class<?> delegateClazz, Map<
.forEach(tv -> {
writer.visitFormalTypeParameter(tv.getName());
SignatureVisitor cb = writer.visitClassBound();
// Class bounds are special and do not require a visitEnd
// even if a new class context is set
Arrays.stream(tv.getBounds()).forEach(b -> visitTypeParameter(b, cb, typeInfo, context));
cb.visitEnd();
});
Expand All @@ -266,12 +268,14 @@ private static String generateGenericClassSignature(Class<?> delegateClazz, Map<
SignatureVisitor iv = writer.visitInterface();
iv.visitClassType(Type.getInternalName(contract));
for(java.lang.reflect.Type t : typeInfo.get(contract.getName()).getActualTypeArguments()) {
SignatureVisitor v;
if(TypeVariable.class.isInstance(t)) {
visitTypeParameter(t, iv, typeInfo, context);
v = iv;
} else {
SignatureVisitor tav = iv.visitTypeArgument(SignatureVisitor.INSTANCEOF);
visitTypeParameter(t, tav, typeInfo, context);
tav.visitEnd();
v = iv.visitTypeArgument(SignatureVisitor.INSTANCEOF);
}
if(visitTypeParameter(t, v, typeInfo, context)) {
v.visitEnd();
}
}
iv.visitEnd();
Expand Down Expand Up @@ -338,6 +342,7 @@ private static Stream<TypeVariable<?>> toTypeVariables(java.lang.reflect.Type t)
* @param sv - the visitor to update with type information
* @param typeInfo - the known type name to type information mapping
* @param context - A mapping of type names to the class which defines them
* @return true if a new class type has been established and an additional close is needed
*/
private static boolean visitTypeParameter(java.lang.reflect.Type t, SignatureVisitor sv, Map<String, ParameterizedType> typeInfo, Map<String, String> context) {
if(t instanceof Class<?>) {
Expand All @@ -346,8 +351,9 @@ private static boolean visitTypeParameter(java.lang.reflect.Type t, SignatureVis
sv.visitBaseType(Type.getDescriptor(clazz).charAt(0));
} else if (clazz.isArray()) {
SignatureVisitor av = sv.visitArrayType();
visitTypeParameter(clazz.getComponentType(), av, typeInfo, context);
// Do not visit the end
if(visitTypeParameter(clazz.getComponentType(), av, typeInfo, context)) {
av.visitEnd();
}
} else {
sv.visitClassType(Type.getInternalName(clazz));
return true;
Expand All @@ -357,10 +363,11 @@ private static boolean visitTypeParameter(java.lang.reflect.Type t, SignatureVis
sv.visitClassType(Type.getInternalName((Class<?>)pt.getRawType()));
Arrays.stream(pt.getActualTypeArguments()).forEach(ta -> {
SignatureVisitor tav = sv.visitTypeArgument(SignatureVisitor.INSTANCEOF);
visitTypeParameter(ta, tav, typeInfo, context);
// Here we must visit the end as we created a new class type context
tav.visitEnd();
if(visitTypeParameter(ta, tav, typeInfo, context)) {
tav.visitEnd();
}
});
return true;
} else if (t instanceof TypeVariable<?>) {
TypeVariable<?> tv = (TypeVariable<?>) t;
t = getPossibleReifiedTypeFor((TypeVariable<?>)t, typeInfo, context);
Expand All @@ -383,8 +390,11 @@ private static boolean visitTypeParameter(java.lang.reflect.Type t, SignatureVis
tav = sv.visitTypeArgument(SignatureVisitor.EXTENDS);
types = wt.getUpperBounds();
}
Arrays.stream(types).forEach(ty -> visitTypeParameter(ty, tav, typeInfo, context));
// Do not visit the end
Arrays.stream(types).forEach(ty -> {
if(visitTypeParameter(ty, tav, typeInfo, context)) {
tav.visitEnd();
}
});
} else {
throw new IllegalArgumentException("Unhandled generic type " + t.getClass() + " " + t.toString());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,100 @@ public void testMultiInterfaceMapper() throws Exception {

}

@SuppressWarnings({ "unchecked", "rawtypes" })
@Test
public void testMultiInterfaceGenericComplex() throws Exception {

TestMultiInterfaceGenericComplex<Object, Object> mi = new TestMultiInterfaceGenericComplex<>();

// Deliberately re-order the interfaces relative to the implements clause
Class<?> proxyClazz = pcl.define("test.MultiInterfaceGenericComplex", mi,
Arrays.asList(MessageBodyWriter.class, MessageBodyReader.class));

assertTrue(MessageBodyReader.class.isAssignableFrom(proxyClazz));
assertTrue(MessageBodyWriter.class.isAssignableFrom(proxyClazz));
Type[] genericInterfaces = proxyClazz.getGenericInterfaces();

assertEquals(2, genericInterfaces.length);

assertTrue(genericInterfaces[0] instanceof ParameterizedType);
ParameterizedType pt = (ParameterizedType) genericInterfaces[0];
assertEquals(MessageBodyWriter.class, pt.getRawType());
TypeVariable<?> tv = (TypeVariable) pt.getActualTypeArguments()[0];
assertEquals("W", tv.getName());
assertArrayEquals(new Type[] {Object.class}, tv.getBounds());

assertTrue(genericInterfaces[1] instanceof ParameterizedType);
pt = (ParameterizedType) genericInterfaces[1];
assertEquals(MessageBodyReader.class, pt.getRawType());
tv = (TypeVariable) pt.getActualTypeArguments()[0];
assertEquals("R", tv.getName());
assertArrayEquals(new Type[] {Object.class}, tv.getBounds());


Object instance = proxyClazz.getConstructor(Supplier.class)
.newInstance((Supplier<?>) () -> mi);

ByteArrayOutputStream baos = new ByteArrayOutputStream();
((MessageBodyWriter) instance).writeTo("ignore me", Object.class, null, null, null, null, baos);

assertArrayEquals(new byte[]{0x42}, baos.toByteArray());


ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());


assertEquals("tada", ((MessageBodyReader) instance).readFrom(Object.class, null, null, null, null, bais));

}

@SuppressWarnings({ "unchecked", "rawtypes" })
@Test
public void testMultiInterfaceGenericComplexTwo() throws Exception {

TestMultiInterfaceGenericComplexTwo<Integer, String> mi = new TestMultiInterfaceGenericComplexTwo<>();

// Deliberately re-order the interfaces relative to the implements clause
Class<?> proxyClazz = pcl.define("test.MultiInterfaceGenericComplexTwo", mi,
Arrays.asList(MessageBodyWriter.class, MessageBodyReader.class));

assertTrue(MessageBodyReader.class.isAssignableFrom(proxyClazz));
assertTrue(MessageBodyWriter.class.isAssignableFrom(proxyClazz));
Type[] genericInterfaces = proxyClazz.getGenericInterfaces();

assertEquals(2, genericInterfaces.length);

assertTrue(genericInterfaces[0] instanceof ParameterizedType);
ParameterizedType pt = (ParameterizedType) genericInterfaces[0];
assertEquals(MessageBodyWriter.class, pt.getRawType());
TypeVariable<?> tv = (TypeVariable) pt.getActualTypeArguments()[0];
assertEquals("W", tv.getName());
assertArrayEquals(new Type[] {CharSequence.class}, tv.getBounds());

assertTrue(genericInterfaces[1] instanceof ParameterizedType);
pt = (ParameterizedType) genericInterfaces[1];
assertEquals(MessageBodyReader.class, pt.getRawType());
tv = (TypeVariable) pt.getActualTypeArguments()[0];
assertEquals("R", tv.getName());
assertArrayEquals(new Type[] {Number.class}, tv.getBounds());

Object instance = proxyClazz.getConstructor(Supplier.class)
.newInstance((Supplier<?>) () -> mi);

ByteArrayOutputStream baos = new ByteArrayOutputStream();
((MessageBodyWriter) instance).writeTo("banana", CharSequence.class, null, null, null, null, baos);

// 4 characters, "anan"
assertArrayEquals(new byte[]{0,4,97,110,97,110}, baos.toByteArray());


ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());


assertEquals(17, ((MessageBodyReader) instance).readFrom(Number.class, null, null, null, null, bais));

}

@Test
public void testMultiInterfaceMapperJerseyStyle() throws Exception {

Expand Down

0 comments on commit 62de133

Please sign in to comment.