我little library的作者使用Mailgun service发送电子邮件。
该库目前有一种非常简单的机制,可以使用某种HTML DSL生成丰富的邮件正文内容。我正在研究下一个版本,我希望提供转换器SPI,以便您可以传递根据需要进行格式化的对象。我正在考虑数字,日期,货币价值等。
我在使用泛型,通配符类型,边界等方面苦苦挣扎。我认为我的问题更多的是一般设计,而不是泛型使用的细节。所以我的问题是,鉴于Java泛型的限制,我应该如何设计我的SPI。
我已经开始定义转换器接口:
public interface ContentConverter<T> {
String toString(T value);
}
整个库中都有一个配置对象。在那里,用户应该使用这种注册方法注册该接口的实例。
public <T> Configuration registerConverter(ContentConverter<? super T> converter,
Class<T> classToConvert)
{
converters.add(new Converter<>(classToConvert, converter));
return this;
}
Converter
类是封装转换器及其类的内部类。
private final static class Converter<T> {
private Class<T> classOfConverter;
private ContentConverter<? super T> contentConverter;
Converter(Class<T> classOfConverter,
ContentConverter<? super T> contentConverter)
{
this.classOfConverter = classOfConverter;
this.contentConverter = contentConverter;
}
}
Configuration
会保留转换器列表。
private List<Converter<?>> converters = ...
最后,配置按需提供转换器。
@SuppressWarnings("unchecked")
public <T> ContentConverter<T> converter(Class<T> classToConvert) {
for (Converter<?> converter : converters)
if (classToConvert.isAssignableFrom(converter.classOfConverter))
return (ContentConverter<T>) converter.contentConverter;
return (ContentConverter<T>) defaultConverter;
}
默认转换器只是调用Object.toString()
。
private final static ContentConverter<Object> defaultConverter =
new ContentConverter<Object>() {
@Override
public String toString(Object value) {
return value.toString();
}
};
当用户构建正文消息时,他可以调用这两种方法中的任何一种来使用配置的转换器添加对象。
public Builder text(Object value) {
ContentConverter<?> converter = configuration.converter(value.getClass());
return text(value, converter);
}
public <T> Builder text(T value, ContentConverter<T> converter) {
return text(converter.toString(value));
}
public Builder text(String s) {
[...] // this is where the content is really appendend
return this;
}
但这并不奏效。第一种方法不能编译。我尝试了不同的组合,但我认为问题更深入,有关该类型的删除。
答案 0 :(得分:0)
只需将第一个text
方法的value参数设为通用。 (你仍然需要为类对象进行强制转换):
public <T> Builder text(T value) {
ContentConverter<T> converter = configuration.converter((Class<T>)value.getClass());
return text(value, converter);
}
答案 1 :(得分:0)
确保您正在进行正确的演员,也是为了价值:
o6
并在您的第一个文字中定义# [o2, o4, o5, o7, o8, o9, o10]
&#39;方法
无论如何,请注意您的代码会产生public <T> Builder text(Object value) {
Configuration configuration = new Configuration();
ContentConverter<T> converter = configuration.converter((Class<T>)value.getClass());
return text((T)value, converter);
}
,因为两个T
方法都是相互调用的,并且永远不会获得任何输出。