Java Spring转换服务-来自列表<;A>;列出<;B>;
我在Spring3应用程序中注册了一个自定义转换服务。它对POJO很有效,但对列表不起作用 例如,我将Java Spring转换服务-来自列表<;A>;列出<;B>;,java,spring,type-conversion,spring-3,Java,Spring,Type Conversion,Spring 3,我在Spring3应用程序中注册了一个自定义转换服务。它对POJO很有效,但对列表不起作用 例如,我将字符串转换为角色,效果很好,但对于列表转换为列表,效果不好 当尝试注入列表时,所有类型的ClassCastExceptions都会飞入应用程序,无论它们包含什么。转换服务将List的转换器调用为List的转换器 如果你仔细想想,这是有道理的。类型擦除是罪魁祸首,转换服务实际上看到了List到List 有没有办法告诉转换服务使用泛型 我还有其他选择吗?我有一个工作要做。这并不是世界上最漂亮的事情,
字符串
转换为角色
,效果很好,但对于列表
转换为列表
,效果不好
当尝试注入列表时,所有类型的ClassCastExceptions
都会飞入应用程序,无论它们包含什么。转换服务将List
的转换器调用为List
的转换器
如果你仔细想想,这是有道理的。类型擦除是罪魁祸首,转换服务实际上看到了List
到List
有没有办法告诉转换服务使用泛型
我还有其他选择吗?我有一个工作要做。这并不是世界上最漂亮的事情,但是如果使用Spring转换服务对你来说很重要的话,它可能会起作用 正如您指出的,问题在于类型擦除。通过ConversionService接口,您可以告诉Spring的最好情况是,您可以将列表转换为列表,而将列表转换为Spring是没有意义的,这就是为什么转换器不能工作的原因(这是我的猜测……换句话说,我不认为这是一个bug) 要执行所需操作,您需要创建并使用泛型接口和/或类的特定于类型的实现:
public interface StringList extends List<String> { }
public class StringArrayList extends ArrayList<String> implements StringList { }
公共接口StringList扩展列表{}
公共类StringArrayList扩展ArrayList实现StringList{}
在本例中,您将使用StringArrayList而不是ArrayList创建列表,并通过ConversionService接口注册实现类(StringArrayList.class)或接口类(StringList.class)。您似乎想要注册该接口。。但是如果您只想注册实现类,那么根本不需要定义接口
我希望这有帮助。拉尔夫是正确的,如果你有一个从
a
转换到B
的转换器,它就可以工作
我不需要将
List
转换为List
我使用的是Spring GenericConversionService
所讨论的转换方法具有以下签名:
public <T> T convert(Object source, Class<T> targetType)
public T convert(对象源,类targetType)
List.class
不是有效的Java语法
这对我很有用:
List<A> sourceList = ...;
conversionService.convert(sourceList, (Class<List<B>>)(Class<?>)List.class);
列表
编辑:
上述措施并没有真正起作用。没有编译错误,但是它导致sourceList未被转换,并被分配给targetList。这导致在尝试使用targetList时下游出现各种异常
我目前的解决方案是扩展Spring的GenericConversionService,并添加我自己的convert方法来处理列表
下面是转换方法:
@SuppressWarnings({"rawtypes", "unchecked"})
public <T> List<T> convert(List<?> sourceList, Class<T> targetClass) {
Assert.notNull(sourceList, "Cannot convert null list.");
List<Object> targetList = new ArrayList();
for (int i = 0; i < sourceList.size(); i++) {
Object o = super.convert(sourceList.get(i), targetClass);
targetList.add(o);
}
return (List<T>) targetList;
}
@SuppressWarnings({“rawtypes”,“unchecked”})
公共列表转换(列表源列表,类targetClass){
Assert.notNull(sourceList,“无法转换空列表”);
List targetList=new ArrayList();
对于(int i=0;i
可以这样称呼它:
List<A> sourceList = ...;
List<B> targetList = conversionService.convert(sourceList, B.class);
List sourceList=。。。;
List targetList=conversionService.convert(sourceList,B.class);
我很想看看是否有人有更好的方法来处理这种常见的情况。我在推土机上也遇到了同样的问题,并发现:
为此,我使用spring转换服务编写了一个简单的实用程序方法:
public static <T, U> List<U> convertList(final ConversionService service, final List<T> source, final Class<U> destType) {
final List<U> dest = new ArrayList<U>();
if (source != null) {
for (final T element : source) {
dest.add(service.convert(element, destType));
}
}
return dest;
}
公共静态列表convertList(最终转换服务、最终列表源、最终类destType){
最终列表dest=new ArrayList();
如果(源!=null){
for(最终T元素:源){
dest.add(service.convert(元素,destType));
}
}
返回目的地;
}
本质上唯一的区别是,它采用spring转换服务,而不是dozer mapper实例。现在可以使用此方法转换具有类型安全性的列表。这与上面Jeff B的回答类似,只是您不需要抑制警告,并且此方法不一定需要属于给定的转换…这是一种实用方法。我遇到了相同的问题,通过执行一点调查,找到了一个解决方案(对我有效)。如果您有两个类A和B,并且有一个已注册的转换器,例如SomeConverter实现了converter,than,要将A列表转换为B列表,您应该执行以下操作:
List<A> listOfA = ...
List<B> listOfB = (List<B>)conversionService.convert(listOfA,
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(A.class)),
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(B.class)));
List listOfA=。。。
List listOfB=(List)conversionService.convert(listOfA,
TypeDescriptor.collection(List.class,TypeDescriptor.valueOf(A.class)),
集合(List.class,TypeDescriptor.valueOf(B.class));
我发现一个相对干净的解决方法是创建一个代理转换器类,该类接受要转换的原始对象,并委托给转换器接口的扩展版本,该接口支持布尔canConvert
语义,以便允许实现决定是否可以转换该源数据或者不是
e、 g:
界面:
public interface SqlRowSetToCollectionConverter<T> extends Converter<SqlRowSet,Collection<T>> {
boolean canConvert (SqlRowSet aSqlRowSet);
}
公共接口SqlRowSetToCollectionConverter扩展转换器{
布尔canConvert(SqlRowSet aSqlRowSet);
}
代理类:
public class SqlRowSetToCollectionConverterService implements Converter<SqlRowSet, Collection<?>> {
private SqlRowSetToCollectionConverter<?>[] converters;
public void setConverters (SqlRowSetToCollectionConverter<?>[] aConverters) {
converters = aConverters;
}
@Override
public Collection<?> convert (SqlRowSet aSource) {
for (SqlRowSetToCollectionConverter<?> converter : converters) {
if (converter.canConvert (aSource)) {
return (converter.convert(aSource));
}
}
return null;
}
}
公共类SqlRowSetToCollectionConverterService实现Converter[]转换器;
public void setConverters(SqlRowSetToCollectionConverter[]a转换器){
转换器=转换器;
}
@凌驾
公共集合转换(SqlRowSet aSource){
用于(SqlRowSetToCollectionConverter转换器:转换器){
if(converter.canConvert(aSource)){
返回(converter.convert(aSource));
}
}
返回null;
}
}
然后我将用Spring的Conv注册代理类
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.hilton.hms.data.convert.SqlRowSetToCollectionConverterService">
<property name="converters">
<bean class="com.hilton.hms.data.convert.SqlRowSetToConfigCollectionConverter" />
</property>
</bean>
</set>
</property>
</bean>
List<A> source = Collections.emptyList();
TypeDescriptor sourceType = TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(A.class));
TypeDescriptor targetType = TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(B.class));
List<B> target = (List<B>) conversionService.convert(source, sourceType, targetType);
public class ExampleConverter implements Converter<A, B> {
@Override
public B convert(A source) {
//convert
}
}
List<B> listB = listA.stream().map(a -> converterService.convert(a, B.class)).collect(Collectors.toList());
@Nullable
public Object convert(@Nullable Object source, TypeDescriptor targetType) {
return convert(source, TypeDescriptor.forObject(source), targetType);
}
public <S, @NonNull T> Collection<T> convert(Collection<S> source, Class<T> targetType) {
return (Collection<@NonNull T>) requireNonNull(conversionService.convert(source, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(targetType))));
}