当前位置: 首页 > 知识库问答 >
问题:

注释类不工作的Java反射

孙帅
2023-03-14
abstract class Identifiable<T, K extends Comparable<K>> implements Comparable<Identifiable<T, K>> {

    @Retention(RetentionPolicy.RUNTIME)
    public @interface Identifier { }

    private static Method getMethodAnnotatedWith(final Class<?> type) {
        return Arrays.stream(type.getDeclaredMethods())
                .filter(m -> m.isAnnotationPresent(Identifier.class))
                .findFirst()
                .orElse(null);
    }

    private K id;

    @SuppressWarnings("unchecked")
    public Identifiable(Class<T> clazz) {
        var m = getMethodAnnotatedWith(clazz);
        if (m == null) throw new IllegalArgumentException(
            clazz.toString() + " does not have a method annotated by @Identifier"
        );

        try {
            id = (K) m.invoke(this);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public int compareTo(@NotNull Identifiable<T, K> i) {
        return id.compareTo(i.id);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Identifiable<?, ?> that = (Identifiable<?, ?>) o;
        return id == that.id;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

class Foo extends Identifiable<Foo, Integer> {
    private final int i;

    Foo(int i) {
        super(Foo.class);
        this.i = i;
    }

    @Identifier
    int getI() {
        return i;
    }
}

但是,由于某种原因,ID总是0,所以我不确定这是identifier注释类的问题还是我使用反射的方式的问题。我很确定是后者,因为在调试时,我发现它能够访问带有注释的方法。如有任何帮助,不胜感激,谢谢!

共有1个答案

戚勇
2023-03-14

不要在构造过程中调用带注释的方法。

如果标识符值是不可变的(final),只需将该值传递给超级构造函数即可。

public Identifiable(K id) {
    this.id = id;
}
Foo(int i) {
    super(i);
    this.i = i;
}

如果标识符值是可变的,则需要更改逻辑以便在需要该值时调用方法,而不是在构造期间缓存该值。

abstract class Identifiable<T, K extends Comparable<K>> implements Comparable<Identifiable<T, K>> {

    @Retention(RetentionPolicy.RUNTIME)
    public @interface Identifier {/**/}

    private Method idGetter;

    protected Identifiable(Class<T> type) {
        this.idGetter = Arrays.stream(type.getDeclaredMethods())
                .filter(m -> m.isAnnotationPresent(Identifier.class))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException(type.getName() + " does not have a method annotated by @Identifier"));
    }

    @SuppressWarnings("unchecked")
    private final K getIdentifiableKey() {
        try {
            return (K) this.idGetter.invoke(this);
        } catch (IllegalAccessException e) {
            throw new IllegalAccessError(e.getMessage());
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public int compareTo(Identifiable<T, K> that) {
        return this.getIdentifiableKey().compareTo(that.getIdentifiableKey());
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        
        Identifiable<?, ?> that = (Identifiable<?, ?>) o;
        return this.getIdentifiableKey().equals(that.getIdentifiableKey()); // Call equals(), don't use ==
    }

    @Override
    public int hashCode() {
        return Objects.hash(this.getIdentifiableKey());
    }
}
abstract class Identifiable<T extends Identifiable<T, K>, K extends Comparable<K>> implements Comparable<Identifiable<T, K>> {

    private Function<T, K> idGetter;

    protected Identifiable(Function<T, K> idGetter) {
        this.idGetter = Objects.requireNonNull(idGetter);
    }

    @Override
    @SuppressWarnings("unchecked")
    public int compareTo(Identifiable<T, K> that) {
        return this.idGetter.apply((T) this).compareTo(that.idGetter.apply((T) that));
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        
        Identifiable<T, K> that = (Identifiable<T, K>) o;
        return this.idGetter.apply((T) this).equals(that.idGetter.apply((T) that));
    }

    @Override
    @SuppressWarnings("unchecked")
    public int hashCode() {
        return Objects.hash(this.idGetter.apply((T) this));
    }
}
class Foo extends Identifiable<Foo, Integer> {
    private final int i;

    Foo(int i) {
        super(Foo::getI);
        this.i = i;
    }

    int getI() {
        return i;
    }
}
 类似资料:
  • 我正在尝试在数据库中保存对象。正在执行代码并创建实体的Id,但实体未持久化到数据库(未插入行): 从三行(beginTransation,flush,commit)中删除注释解决了问题,但是为什么注释在这里不起作用呢? spring XML: POM xml文件:

  • 我在玩和 这是我的应用程序上下文文件 以下是我的Java类 HelloWorld1。JAVA 住址JAVA 这里是我尝试运行东西的地方-应用程序。JAVA 我一直在得到这个异常-理想情况下我不应该,因为我已经定义了id为'address1'的@Qualifier注释-所以它不应该抛出异常 警告:上下文初始化过程中遇到的异常-取消刷新尝试:org.springframework.beans.fact

  • 我的spring应用程序有点小问题。下面是我的代码: (存储库) 下面是我的简单服务类: 更新:配置

  • 我将Spring 3.2.4与JavaFX结合使用,并希望实现一种方法,其中操作将在事务中执行。我在控制器中的代码如下所示: 以及我的应用程序上下文: 尝试运行时,我收到以下错误消息: 该方法存在。删除注释,或者将方法从public更改为private,或者从配置中删除bean,程序就会运行,但事务注释根本不起作用。删除代理目标会导致另一个错误。

  • 你好,朋友,我正在开发基于spring(4.0.3)和hibernate(4.3.6)的应用程序。在会话工厂中保存任何对象时,我遇到以下错误: 下面是我在application-context.xml中使用的条目 还有一件事我想带到这里,如果我在事务管理器属性中使用了任何值,而不是实际的transactionManager作为bean引用,那么这不是抛出错误。所以我认为它没有参考价值<请帮帮我!!