繁体   English   中英

枚举感知 ServiceLoader 实现?

[英]Enum-aware ServiceLoader implementation?

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

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

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

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存在并且有 next,它会在移动到下一个类名之前迭代。

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

如果最终用途不清楚,现在可以通过上述修改实现:

interface ImageType {
    String name();
}

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

随着 Java 模块的引入,服务提供者添加了通过默认构造函数进行实例化的替代方法 但它仅在提供程序位于命名模块中时才有效。

提供者类可以声明一个public static T provider()方法,其中T是服务类型。 然后,提供者实现类甚至不需要实现或扩展T本身。

由于数组和List<ImageType>类的泛型类型都不能用作服务类型,因此我们需要另一种类型来潜在地封装多个实际实例,例如

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());

模块内的某处(或任何其他具有uses somemodule.ImageType.ImageTypes;声明的模块)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM