枚举可识别的ServiceLoader实现?

时间:2019-02-16 04:00:42

标签: java enums serviceloader

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

例如,Java NIO API中的CopyOption接口,带有提供的StandardCopyOption枚举。假设我想通过CopyOption将所有ServiceLoader,甚至是标准路径上的所有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

我还添加了一些代码,使得如果interface ImageType { String name(); } @AutoService(ImageType.class) enum StandardImageType implements ImageType { IMAGE, VECTOR, RASTER, HANDWRITING, ICON, LOGO, SEAL, RULE, BARCODE } 存在并具有下一个,则在继续下一个类名之前对其进行迭代。

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

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

BoundaryNorm

1 个答案:

答案 0 :(得分:3)

随着Java模块的引入,通过默认构造函数实例化的an alternative已添加到服务提供商。但是,只有当提供程序位于命名模块中时,它才起作用。

提供者类可以声明一个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;声明的任何其他模块)。