枚举感知的ServiceLoader实现? [英] Enum-aware ServiceLoader implementation?

查看:147
本文介绍了枚举感知的ServiceLoader实现?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望能够将枚举类型表示为接口实现,然后通过 ServiceLoader API将所有枚举加载为接口的单独实例/实现。该用例的一个示例是允许我的API的下游用户指定自定义值,但为枚举提供标准/通用实现。我的界面只需要一个字符串 name(),因此任何枚举都已经实现了它。

I would like to be able to indicate an enum type as an interface implementation and then load all enums as separate instances/implementations of the interface via the ServiceLoader API. An example of this use case would be to allow downstream users of my API to specify custom values, but provide an enum with standard/common implementations. My interface only requires a String name(), so any enum implements it already.

例如,< Java NIO API中的code> CopyOption 接口,带有提供的 StandardCopyOption 枚举。假设我想通过 ServiceLoader CopyOption 甚至是类路径上的新内容以及标准一起加载到单个迭代器中c>(或者我愿意接受其他建议!)

For example, the CopyOption interface in the Java NIO APIs, with the provided StandardCopyOption enum. Say I wanted to load all CopyOptions, even new ones on the classpath along with the standards, to a single iterator via ServiceLoader (or I'm open to other suggestions!)

我终于通过批量复制 ServiceLoader 并对其进行修改,以在实例化失败时尝试使用 getEnumConstants try 中的部分是当前的工作方式以及 catch 的一部分就是我添加/更改的内容:

I finally got it to work by wholesale copying ServiceLoader and modifying it to try using getEnumConstants when instantiation fails (the part in the try is how it works currently and the part in the catch is what I added/changed):

try {
    S p = service.cast(c.newInstance());
    providers.put(cn, p);
    return p;
} catch (Throwable x) {
    Object[] arr = c.getEnumConstants();
    if (arr == null || arr.length == 0) {
        fail(service, "Provider " + cn + " could not be instantiated", x);  
    }

    List<S> list = new LinkedList<>();
    for (Object o : arr) {
        Enum<?> e = (Enum<?>) o;
        S p = service.cast(e);
        providers.put(cn + e.ordinal(), p);
        list.add(p);
    }
    subiter = list.iterator();
    return subiter.next();
}

我还添加了一些代码,例如 subiter 存在并具有下一个,它会在进入下一个类名之前进行迭代。

I also added some code such that if subiter exists and has next, it is iterated before moving on to the next class name.

我的问题是:有没有更好的方法?

如果最终用途不清楚,则可以进行上述修改:

In case the end use is not clear, this is now what's possible with the above modifications:

interface ImageType {
    String name();
}

@AutoService(ImageType.class)
enum StandardImageType implements ImageType {
    IMAGE,
    VECTOR,
    RASTER,
    HANDWRITING,
    ICON,
    LOGO,
    SEAL,
    RULE,
    BARCODE
}


推荐答案

引入Java模块后,通过默认构造函数实例化的替代方法已添加到服务提供商。

With the introduction of Java modules, an alternative to instantiating via default constructor has been added to service providers. But it only work when the provider is in a named module.

provider类可以声明公共静态T provider()方法,其中 T 是服务类型。然后,提供程序实现类甚至不需要自身实现或扩展 T

The provider class may declare a public static T provider() method where T is the service type. Then, the provider implementation class doesn’t even need to implement or extend T itself.

也不能使用 List< ImageType> 之类的通用类型作为服务类型,我们需要另一种类型来潜在地封装多个实际实例,例如

Since neither, arrays nor a generic type like List<ImageType> can be used as service type, we would need another type for potentially encapsulating multiple actual instances, e.g.

package somemodule;

import java.util.function.Supplier;

public interface ImageType {
    String name();
    interface ImageTypes extends Supplier<ImageType[]> {}
}

package somemodule;

public enum StandardImageType implements ImageType {
    IMAGE,
    VECTOR,
    RASTER,
    HANDWRITING,
    ICON,
    LOGO,
    SEAL,
    RULE,
    BARCODE;

    public static ImageTypes provider() {
        return StandardImageType::values;
    }
}

和类似模块声明的

module SomeModule {
    uses somemodule.ImageType.ImageTypes;
    provides somemodule.ImageType.ImageTypes with somemodule.StandardImageType;
}

可以写,例如

List<ImageType> all = ServiceLoader.load(ImageType.ImageTypes.class)
        .stream().flatMap(p -> Arrays.stream(p.get().get()))
        .collect(Collectors.toList());

模块内的某个位置(或任何其他模块使用somemodule.ImageType .ImageTypes; 声明)。

somewhere within the module (or any other module with a uses somemodule.ImageType.ImageTypes; declaration).

这篇关于枚举感知的ServiceLoader实现?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆