java - 在 Java 中使用 Class<T> 作为注释的属性

标签 java

我们正在尝试创建 Cache 的基本实现。在 java 。为此,我们创建了一个注释 @Cached定义为:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Cached {

    <T> Class<T> keyClass();

    <V> Class<V> valueClass();

    String cacheId();
}

这会导致错误:@interface members may not have type parameters .然而,这是必需的,因为我们希望对返回方法的值进行类型转换并将它们存储在缓存中。我们正在使用 AspectJ用于拦截需要缓存结果的方法调用。
我们可以获得结果的另一种方式是什么?由于并非所有方法都具有相同的签名,因此我们必须依赖标记为 @Cached 的方法。对于我们的缓存实现。

更新
这是在缓存中存储数据的类:
public class Cache<K extends Serializable, V> {
   private Map<K, CacheEntry<V> cache;
   // Some other fields and accessors
}

类(class)CacheEntry定义为:
public class CacheEntry<V> {
   private V value;
   // Some other fields used for invalidating the cache entry and accessors
}

现在在访问缓存时,我想做这样的事情:
cache.getCache().values().stream()
        .map(value -> cached.valueClass().cast(value))
        .collect(Collectors.toList());

在上面的代码中,cached@Cached的引用方法上使用的注释为:
@Cached(keyClass = Long.class, valueClass = Person.class, cacheId = "personCache")
List<Person> findAll();

最佳答案

cached.valueClass().cast(value)在这种情况下无法帮助您,主要是因为编译器无法强制执行 cached.valueClass()兼容 Cached.valueClass() .

通过类型转换帮助缓存客户端的最佳方法是让它们在读取时指定目标类型:

public <V> List<V> getAllCachedValues(Class<V> valueClass) {
    return cache.getCache().values().stream()
    .map(value -> valueClass.cast(value))
    .collect(Collectors.toList());
}

或使用此未经检查的类型转换:
public <V> List<V> getAllCachedValues() {
    return cache.getCache().values().stream()
    .map(value -> (V) value)
    .collect(Collectors.toList());
}

以下是一些用于说明尝试使用注释强制执行类型安全是多么不切实际的用法:
  • 您不能强制返回类型和注释元数据之间的兼容性:
    @Cached(keyClass = Long.class, valueClass = Person.class, cacheId = "personCache")
    List<Banana> findAll();
    
  • 客户可以选择 TV与实际缓存实例相关联(否则这将毫无意义,对吧?)。话虽如此,这是可能的:
    @Cached(keyClass = Long.class, valueClass = Person.class, cacheId = "personCache")
    
    //and then
    Cache<Long, Banana> cacheInstance = cacheManager.getCache("personCache");
    

    当然,您可以添加 Class getCache 的参数:
    Cache<Long, Banana> cacheInstance = cacheManager.getCache("personCache", 
                        Long.class, Banana.class);
    

    并使用实际 Class 进行验证实例。但是,当您可以采用第一种方法(在检索时强制转换)时,这样做的意义何在……底线是调用者将最终确保类型兼容性,而注释元数据无济于事。

  • 在我看来,@Cached(keyClass = Long.class, valueClass = Person.class, cacheId = "personCache")如果您将缓存值序列化为 JSON 和 XML 等格式,并且需要原始类在缓存被命中时反序列化它们,则可能有助于输入(当然,希望客户端进行转换)。

    关于java - 在 Java 中使用 Class<T> 作为注释的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58518232/

    相关文章:

    java - 为什么在实例(Java)上调用方法时不需要导入类

    java - 使用堆栈的回文类的问题

    Java:如何在数组列表中搜索数组中对象的实例变量

    java - 关于Spring事务管理重新设计的建议

    java - Java 中字符串的替换

    java - 是否可以使用不同的返回和参数类型进行递归

    java - 如何排列 int[] 并将每个 int[] 保存到 int[][] 中?

    java - Apache tiles 将没有内容的打开标签和关闭标签转换为空标签

    java - 抽象类中的 protected 数据

    java - 如何使用 Selenium 在 PhantomJS 中设置代理身份验证?