SpEL:如何获取表达式的类型(不是它的值)

时间:2015-04-08 21:29:43

标签: java spring-el

我正在尝试使用spell来获取表达式的类型而不是实际的实例值。我不认为这是可能的,但我想把它扔出去。

考虑:

public interface Foo {

    Integer getAge();

    String getFamilyName();

    String getGivenName();

    Set<Integer> getSomeData();

    Set<Baz> getBazez();

    Baz getAnyBaz();
}
public interface Baz {
    Integer getBat();

    Integer getWhatever();
}

一些测试

    @Test
    public void testNestedMemberDataType() throws Exception {
        ExpressionParser parser = new SpelExpressionParser();

        EvaluationContext context = new StandardEvaluationContext();

        Expression exp = parser.parseExpression("anyBaz.bat");
        Class<?> valueType = exp.getValueType(context);
        assertEquals(Integer.class,valueType);

    }

   @Test
    public void testNestedMemberDataTypeSet() throws Exception {
        ExpressionParser parser = new SpelExpressionParser();

        EvaluationContext context = new StandardEvaluationContext();
        // this is not valid spell syntax but I would like to do this
        // to indicate the type inside the collection
        Expression exp = parser.parseExpression("bazez[*].bat");
        Class<?> valueType = exp.getValueType(context);
        assertEquals(Integer.class,valueType);

    }

1 个答案:

答案 0 :(得分:0)

我最终实际上是这样实现的:

 @Override
    public Class<?> getDeclaredTypeFor(String attribute) {
        Class<?> finalType = entityType;
        List<String> nestings = Arrays.asList(attribute.split("\\."));
        PropertyDescriptor d = null;
        Iterator<String> iter = nestings.iterator();
        while (iter.hasNext()) {
            String nesting = iter.next();
            d = BeanUtils.getPropertyDescriptor(finalType, nesting);
            if (d == null) {
                Set<Class> allTypes = allTypesFor(finalType, new LinkedHashSet<>());
                d = allTypes.stream().map(t -> BeanUtils.getPropertyDescriptor(t, nesting)).filter(p -> p != null).findFirst().orElse(null);
                if (d == null)
                    break;
            }
            if (iter.hasNext() && isTypeACollection(d.getReadMethod().getGenericReturnType())) {
                finalType = getGenericType(d.getReadMethod().getGenericReturnType(), true);
            } else {
                finalType = d.getPropertyType();
            }
        }
        return d == null ? null : finalType;

    }

    private Class getGenericType(Type t, boolean isCollection) {
        Class clazz;
        if (isCollection) {
            Type type = ((ParameterizedType) t).getActualTypeArguments()[0];

            if (type instanceof WildcardType) {
                type = ((WildcardType) type).getUpperBounds()[0];
            } else if(type instanceof TypeVariable) {
                type = ((TypeVariable) type).getBounds()[0];
            }

            clazz = (Class) type;
        } else if (t instanceof Class) {
            clazz = (Class) t;
        } else {
            throw new RuntimeException("Don't know how to handle " + t.getClass());
        }
        return clazz;
    }

    private boolean isTypeACollection(Type t) {
        boolean isPossible = t instanceof ParameterizedType;

        if (isPossible)
            isPossible = Collection.class.isAssignableFrom((Class) ((ParameterizedType) t).getRawType());

        return isPossible;
    }

    private static Set<Class> allTypesFor(Class c, Set<Class> types) {
        types.add(c);
        Class superclass = c.getSuperclass();
        if (superclass != null)
            allTypesFor(superclass, types);

        for (Class iFace : c.getInterfaces()) {
            allTypesFor(iFace, types);
        }
        return types;
}