Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/385.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring转换服务-来自列表<;A>;列出<;B>;_Java_Spring_Type Conversion_Spring 3 - Fatal编程技术网

Java Spring转换服务-来自列表<;A>;列出<;B>;

Java Spring转换服务-来自列表<;A>;列出<;B>;,java,spring,type-conversion,spring-3,Java,Spring,Type Conversion,Spring 3,我在Spring3应用程序中注册了一个自定义转换服务。它对POJO很有效,但对列表不起作用 例如,我将字符串转换为角色,效果很好,但对于列表转换为列表,效果不好 当尝试注入列表时,所有类型的ClassCastExceptions都会飞入应用程序,无论它们包含什么。转换服务将List的转换器调用为List的转换器 如果你仔细想想,这是有道理的。类型擦除是罪魁祸首,转换服务实际上看到了List到List 有没有办法告诉转换服务使用泛型 我还有其他选择吗?我有一个工作要做。这并不是世界上最漂亮的事情,

我在Spring3应用程序中注册了一个自定义转换服务。它对POJO很有效,但对列表不起作用

例如,我将
字符串
转换为
角色
,效果很好,但对于
列表
转换为
列表
,效果不好

当尝试注入列表时,所有类型的
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))));
}