private static Stream<MetaClass> getConcreteBounds(final MetaType[] bounds) { return Arrays .stream(bounds) .flatMap(bound -> { if (bound instanceof MetaClass) { return Collections.singletonList(bound).stream(); } else if (bound instanceof MetaTypeVariable) { final MetaTypeVariable mtv = (MetaTypeVariable) bound; return getConcreteBounds(mtv.getBounds()); } else { return Collections.emptyList().stream(); } }).map(mt -> (MetaClass) mt); }
private static Stream<MetaClass> getConcreteBounds(final MetaType[] bounds) { return Arrays .stream(bounds) .flatMap(bound -> { if (bound instanceof MetaClass) { return Collections.singletonList(bound).stream(); } else if (bound instanceof MetaTypeVariable) { final MetaTypeVariable mtv = (MetaTypeVariable) bound; return getConcreteBounds(mtv.getBounds()); } else { return Collections.emptyList().stream(); } }).map(mt -> (MetaClass) mt); }
private MetaClass getTypeOrFirstUpperBound(MetaType clazz, final MetaMethod method) { if (clazz instanceof MetaTypeVariable) { final MetaType[] bounds = ((MetaTypeVariable) clazz).getBounds(); if (bounds.length == 1 && bounds[0] instanceof MetaClass) { clazz = ((MetaTypeVariable) clazz).getBounds()[0]; } else { // TODO add full support for generics in errai codegen logger.log(TreeLogger.WARN, "Ignoring method: " + method + " in class " + bindable + ". Methods using " + "multiple type parameters or type parameters with multiple bounds are currently not supported in " + "@Bindable types! Invoking this method on a bound model will have unpredictable results."); return null; } } else if (clazz instanceof MetaParameterizedType) { clazz = ((MetaParameterizedType) clazz).getRawType(); } if (clazz instanceof MetaClass) { return (MetaClass) clazz; } logger.log(TreeLogger.WARN, "Ignoring method: " + method + " in class " + bindable + ". Method cannot be proxied!"); return null; }
private MetaClass getTypeOrFirstUpperBound(MetaType clazz, final MetaMethod method) { if (clazz instanceof MetaTypeVariable) { final MetaType[] bounds = ((MetaTypeVariable) clazz).getBounds(); if (bounds.length == 1 && bounds[0] instanceof MetaClass) { clazz = ((MetaTypeVariable) clazz).getBounds()[0]; } else { // TODO add full support for generics in errai codegen logger.log(TreeLogger.WARN, "Ignoring method: " + method + " in class " + bindable + ". Methods using " + "multiple type parameters or type parameters with multiple bounds are currently not supported in " + "@Bindable types! Invoking this method on a bound model will have unpredictable results."); return null; } } else if (clazz instanceof MetaParameterizedType) { clazz = ((MetaParameterizedType) clazz).getRawType(); } if (clazz instanceof MetaClass) { return (MetaClass) clazz; } logger.log(TreeLogger.WARN, "Ignoring method: " + method + " in class " + bindable + ". Method cannot be proxied!"); return null; }
final boolean hasAssignableUpperBound = getConcreteBounds(((MetaTypeVariable) from).getBounds()) .filter(fromBound -> fromBound.isAssignableFrom((MetaClass) to)) .findAny()
final boolean hasAssignableUpperBound = getConcreteBounds(((MetaTypeVariable) from).getBounds()) .filter(fromBound -> fromBound.isAssignableFrom((MetaClass) to)) .findAny()
@Test public void testFieldWithSingleUpperBoundedTypeVarParam() throws Exception { final MetaClass metaClass = getMetaClass(ClassWithGenericCollections.class); final MetaMethod field = metaClass.getDeclaredMethod("hasSingleBoundedTypeVarFromSelf", new Class[] {}); assertNotNull(field); final MetaTypeVariable returnType = (MetaTypeVariable) field.getGenericReturnType(); assertEquals("B", returnType.getName()); assertEquals("Should have a single upper bound", Arrays.asList(getMetaClass(Serializable.class)), Arrays.asList(returnType.getBounds())); }
@Test public void testFieldWithTwoUpperBoundedTypeVarParam() throws Exception { final MetaClass metaClass = getMetaClass(ClassWithGenericCollections.class); final MetaMethod field = metaClass.getDeclaredMethod("hasDoubleBoundedTypeVarFromSelf", new Class[] {}); assertNotNull(field); final MetaTypeVariable returnType = (MetaTypeVariable) field.getGenericReturnType(); assertEquals("B", returnType.getName()); assertEquals("Should have two upper bounds", Arrays.asList(getMetaClass(Collection.class), getMetaClass(Serializable.class)), Arrays.asList(returnType.getBounds())); }
@Test public void testFieldWithUnboundedTypeVarParam() throws Exception { final MetaClass metaClass = getMetaClass(ClassWithGenericCollections.class); final MetaField field = metaClass.getDeclaredField("hasUnboundedTypeVarFromClass"); assertNotNull(field); assertEquals("Collection", field.getType().getName()); assertEquals("java.util.Collection", field.getType().getFullyQualifiedName()); assertEquals("java.util.Collection<T>", field.getType().getParameterizedType().getName()); assertEquals("java.util.Collection<T>", field.getType().getFullyQualifiedNameWithTypeParms()); assertEquals("java.util.Collection", field.getType().getErased().getFullyQualifiedNameWithTypeParms()); assertEquals(1, field.getType().getParameterizedType().getTypeParameters().length); final MetaTypeVariable typeVar = (MetaTypeVariable) field.getType().getParameterizedType().getTypeParameters()[0]; assertEquals("T", typeVar.getName()); assertEquals("Should have no upper bound", Arrays.asList(getMetaClass(Object.class)), Arrays.asList(typeVar.getBounds())); }