当前位置: 首页 > 面试题库 >

如果在List或Map中注释数组,则Java 8 TYPE_USE注释将不起作用

袁英豪
2023-03-14
问题内容

我正在尝试编写一个带有批注的简单验证库,该批注使用Java
8中的新TYPE_USE目标。访问这些内容的方法确实很复杂,给我留下了两个非常混乱的代码,它们执行的功能完全相同,但同时与他们的实际意图紧密相关。因此,我决定创建一组简单的类,以非常简单和直观的方式保存此信息。基本上有TypedClass,它是一个Class包装器,但是可以将其强制转换为ListClass(集合或数组)或MapClass,以TypedClass的形式访问其组件(或键/值)。最重要的部分是应该转换的此帮助程序:

static TypedClass<?> create(Field f) {
    final TypeResolver typeResolver = new TypeResolver();
    ResolvedType type = typeResolver.resolve(f.getGenericType());
    return create(f.getAnnotations(), type, f.getAnnotatedType());
}

private static TypedClass<?> create(Annotation[] annotations, ResolvedType type, AnnotatedType at) {
    if (type.isArray()) {
        AnnotatedType childAnnotatedType = ((AnnotatedArrayType) at).getAnnotatedGenericComponentType();
        ResolvedType childType = type.getArrayElementType();
        return new ListClass<>(type.getErasedType(), annotations, create(at.getAnnotations(), childType, childAnnotatedType));
    } else if (type.isInstanceOf(Collection.class)) {
        AnnotatedType childAnnotatedType = ((AnnotatedParameterizedType) at).getAnnotatedActualTypeArguments()[0];
        ResolvedType childType = type.typeParametersFor(Collection.class).get(0);
        return new ListClass<>(type.getErasedType(), annotations, createForGenerics(childType, childAnnotatedType));
    } else if (type.isInstanceOf(Map.class)) {
        AnnotatedType[] att = ((AnnotatedParameterizedType) at).getAnnotatedActualTypeArguments();
        List<ResolvedType> types = type.typeParametersFor(Map.class);
        TypedClass<?> key = createForGenerics(types.get(0), att[0]);
        TypedClass<?> value = createForGenerics(types.get(1), att[1]);
        return new MapClass<>(type.getErasedType(), annotations, key, value);
    }
    return new TypedClass<>(type.getErasedType(), annotations);
}

private static TypedClass<?> createForGenerics(ResolvedType childType, AnnotatedType childAnnotatedType) {
    return create(childAnnotatedType.getAnnotations(), childType, childAnnotatedType);
}

在这里,我还使用com.fasterxml.classmate中的ResolvedType,它仅用于在Java中的Type和Class之间架起桥梁,这也是一个痛苦。我认为这与问题无关,因为生成的结构还可以,只有注释放错了位置。

看起来工作还不错,除非List或Map中有一个数组。例如:

@First("array") List<@First("string") String> @First("list") [] arrayOfListOfString;

工作正常(注释与相应的类型匹配)。但是当我解析

List<@First("int[]") Integer @First("int") []> listOfArrayOfInteger;

数组和整数都与@First(“ int”)批注关联。

我已经调试了代码,在任何地方都找不到对@First(“ int
[]”)批注的引用。我或者缺少一些非常简单的东西,或者没有任何意义。该代码似乎可以在所有其他情况下使用,甚至是更复杂的情况。我已经尝试了好几个星期,直到最近才找到我认为可行的解决方案。原来,我之前使用的两种耦合方法在这种情况下也不起作用(没有进行此特定测试)。所以现在我很困。

怎么了?


问题答案:

在您的初始通话中,create您传递的是 字段 注释,而不是的注释AnnotatedType at。因此,该方法create负责调用at.getAnnotations()。如果看一下实现,您会发现它只会在数组情况下这样做。在所有其他情况下,您的方法将逻辑切换为“传入的注释数组是与关联的数组at”。

问题在于您的第一个示例似乎偶然地起作用。您没有显示@First注释的声明,但我怀疑@Targets ElementType.FIELD
都允许使用ElementType.TYPE_USE。在这种情况下,形式的声明

@First("array") List… [] fieldName;

是不明确的并且注释将被记录为 两个
,一个字段注释fieldName和用于注释List…[]类型。因此,在第一个示例中无法识别递归过程中丢失一个注释数组的事实,因为它恰好与字段注释匹配。但是,一旦TYPE_USE只允许注释而不是FIELD目标注释,则您的代码甚至无法与第一个示例一起使用。

因此,您必须确定传入的批注数组是与at参数关联的数组还是与周围上下文关联的数组。如果两者都关联起来会更容易,因为在这种情况下,您可以通过让方法检索该数组而不是调用方来完全摆脱该参数。

您应该记住:

  1. 如果要记录递归类型的所有类型注释 字段注释,则注释数组将比类型节点多一个
  2. 如果要TYPE_USE主要处理注释,则根本不需要处理字段注释

这是一个简单,直接的解析代码,可查找所有注释:

public static void fullType(Field f) {
    AnnotatedType at = f.getAnnotatedType();
    fullType("\t", at);
    System.out.println(f.getName());
}
public static void fullType(String header, AnnotatedType at) {
    final boolean arrayType = at instanceof AnnotatedArrayType;
    if(arrayType) {
        fullType(header+"\t",
            ((AnnotatedArrayType)at).getAnnotatedGenericComponentType());
    }
    for(Annotation a: at.getAnnotations())
        System.out.println(header+a);
    if(arrayType) {
        System.out.println(header+"[]");
    }
    else if(at instanceof AnnotatedParameterizedType) {
        AnnotatedParameterizedType apt = (AnnotatedParameterizedType)at;
        System.out.println(header
            +((ParameterizedType)apt.getType()).getRawType().getTypeName());
        System.out.println(header+'<');
        String subHeader=header+"\t";
        for(AnnotatedType typeArg:
            apt.getAnnotatedActualTypeArguments())
            fullType(subHeader, typeArg);
        System.out.println(header+'>');
    }
    else if(at instanceof AnnotatedTypeVariable) {
        // when appearing in a Field’s type, it refers to Class’ type variables
        System.out.println(header+at.getType().getTypeName());
    }
    else if(at instanceof AnnotatedWildcardType) {
        System.out.println(header+"?");
        final AnnotatedWildcardType awt = (AnnotatedWildcardType)at;
        AnnotatedType[] bounds=awt.getAnnotatedLowerBounds();
        if(bounds==null || bounds.length==0) {
            bounds=awt.getAnnotatedUpperBounds();
            if(bounds==null || bounds.length==0) return;
            System.out.println(header+"extends");
        }
        else System.out.println(header+"super");
        header+="\t";
        for(AnnotatedType b: bounds) fullType(header, b);
    }
    else {
        assert at.getType().getClass()==Class.class;
        System.out.println(header+at.getType().getTypeName());
    }
}

它可以完美地与您的示例字段一起使用。



 类似资料:
  • 我有一个简单的类叫BeaconDao 然而,当我用@service或@component标记beaconDao时,一切都运行得非常好。有人能看出问题所在吗?

  • 问题内容: 我正在尝试使用Java批注,但似乎无法使我的代码认识到其中存在。我究竟做错了什么? 问题答案: 您需要使用注释界面上的@Retention注释将注释指定为运行时注释。 即

  • 问题内容: 我知道有一些关于此的帖子,但是它们大约一年了,没有任何回应。实际上,我们在PostgreSQL 8.4上使用的是Hibernate 4.2.1.Final。我们有两个这样的实体 实体A(顶级层次结构类) 实体B(子类) 如您所见,使用注释了一个实体,但是当使用来获取顶级类时 我们也通过属性获得了B子类。实际上,SQL语句包含。这仍然是Hibernate第四版中的错误,还是我做错了什么?

  • 问题内容: 我从Spring Framework开始,想做一个带有注释的HelloWorld,我已经创建了一个控制器和一个视图,我猜它是基本的hello工作。但是,我想使用注释,因为我不能再使用SimpleFormController(已弃用)。 我收到的错误是Estado HTTP 404-/av/index.jsp 我正在使用Netbeans,并将示例基于它提供的基本模板。我有以下文件,我可以

  • 我有3个测试类如下: 包裹通讯。朱尼特。测试用例; Test3类: Test2类: Test1类: 和一个TestSuite类: 问题是它在从eclipse从JUnit运行TestSuite1类时忽略了Test3类中的@规则标签,因此输出不如预期。为什么它忽略了@规则标签。有没有其他选择来执行所有三种情况?