Web services JavaCXF:处理不同包或名称空间下的公共对象的最佳方法是什么?

Web services JavaCXF:处理不同包或名称空间下的公共对象的最佳方法是什么?,web-services,java-8,cxf,wsdl2java,apache-commons-beanutils,Web Services,Java 8,Cxf,Wsdl2java,Apache Commons Beanutils,我们正在与第三方Web服务集成,使用Wsdl2Java将其模式和端点转换为Java,以提供三种不同的Web服务 这个特定的提供者使用了很多相同的对象(比如表示地址、金钱、权重等的对象),但是,在他们无限的智慧中,他们决定为每个Web服务创建不同的名称空间,并为每个Web服务复制模式的定义。结果是,您有以下用于CXF集成的类输出: com.thirdpartyguys.api.firstApi.Money com.thirdpartyguys.api.secondApi.Money com.thi

我们正在与第三方Web服务集成,使用Wsdl2Java将其模式和端点转换为Java,以提供三种不同的Web服务

这个特定的提供者使用了很多相同的对象(比如表示地址、金钱、权重等的对象),但是,在他们无限的智慧中,他们决定为每个Web服务创建不同的名称空间,并为每个Web服务复制模式的定义。结果是,您有以下用于CXF集成的类输出:

com.thirdpartyguys.api.firstApi.Money

com.thirdpartyguys.api.secondApi.Money

com.thirdpartyguys.api.thirdApi.Money

将我们的数据转换为他们的数据可能涉及很多业务逻辑,因此,我们必须定义代码,为每个单独的Webservice API创建一式三份的对象

为了解决这个问题,我创建了一个定义如下的接口:

import org.apache.commons.beanutils.BeanUtils;
public interface CommonObjectInterface<A, R, S> {
    
    A toFirstApi();
    
    R toSecondApi();
    
    S toThirdApi();
    
    default Object doTransform(Object destination, Object source) {
        try {
            BeanUtils.copyProperties(destination, source);
        } catch (Exception e) {
            throw new RuntimeException("Fatal error transforming Object", e);
        }
        return destination;
    }
    
}
import org.apache.commons.beanutils.beanutils;

公共接口CommonObjectInterface,但我不知道自从有人问起是否出现了更好的解决方案。我认为最好的方法是配置wsdl2Java,以允许在运行时设置名称空间,但从我最初的研究来看,这似乎是不可能的。

此问题的解决方案特定于这种情况:

1) 在不同命名空间中具有相同对象的Web服务提供程序 2) 使用wsdl2Java或一些底层apachecxf技术生成用于编写客户机的web工件

这是一个边缘案例,所以我不确定这对社区会有多大帮助,但诀窍是解释一些copyProperties方法不起作用的情况。在本例中,我使用的是Spring的BeanUtils和BeanRapper类,尽管我确信这也适用于Apache。下面的代码实现了这一点:

final String TARGET_PACKAGE = "com.thirdpartyguys.api";
public Object doTransform(Object destination, Object source) {
    /*
     * This will copy all properties for the same data type for which there is a getter method in
     * source, and a setter method in destination
     */
    BeanUtils.copyProperties(source, destination);

    BeanWrapper sourceWrapper = new BeanWrapperImpl(source);
    for(PropertyDescriptor p : sourceWrapper.getPropertyDescriptors()) {
        /*
         * Properties that are references to other schema objects are identical in structure, but have
         * different packages. We need to copy these separately
         */
        if(p.getPropertyType().getPackage().getName().startsWith(TARGET_PACKAGE)) {
            try {
                commonPropertyCopy(destination, source, p);
            } catch (Exception e) {
                throw new RuntimeException("Fatal error creating Data", e);
            }
        }
        /*
         * Properties that reference list don't create setters according to the Apache CXF
         * convention. We have to call the get method and addAll()
         */
        else if(Collection.class.isAssignableFrom(p.getPropertyType())) {
            try {
                collectionCopy(destination, source, p);
            } catch (Exception e) {
                throw new RuntimeException("Fatal error creating Data", e);
            }
        }
    }
    return destination;
}

private void collectionCopy(Object destination, Object source, PropertyDescriptor sourceProperty) throws Exception {
    BeanWrapper destWrapper= new BeanWrapperImpl(destination);
    PropertyDescriptor destProperty = destWrapper.getPropertyDescriptor(sourceProperty.getName());
    Collection<?> sourceCollection = (Collection<?>) sourceProperty.getReadMethod().invoke(source);
    Collection<Object> destCollection = (Collection<Object>) destProperty.getReadMethod().invoke(destination);
    destCollection.addAll(sourceCollection);

}

private void commonPropertyCopy(Object destination, Object source, PropertyDescriptor sourceProperty) throws Exception {
    if(sourceProperty.getPropertyType().isEnum()) {
        instantiateEnum(destination, source, sourceProperty);
    }
    else {
        instantiateObject(destination, source, sourceProperty);
    }
}

private void instantiateEnum(Object destination, Object source, PropertyDescriptor sourceProperty) throws Exception {
    BeanWrapper destWrapper= new BeanWrapperImpl(destination);
    Enum<?> sourceEnum = (Enum<?>) sourceProperty.getReadMethod().invoke(source);
    PropertyDescriptor destProperty = destWrapper.getPropertyDescriptor(sourceProperty.getName());

    Object enumValue = Enum.valueOf(destProperty.getPropertyType().asSubclass(Enum.class), sourceEnum.name());
    destProperty.getWriteMethod().invoke(destination, enumValue);
}

private void instantiateObject(Object destination, Object source, PropertyDescriptor sourceProperty) throws Exception {
    Object subObj = sourceProperty.getReadMethod().invoke(source);
    if(subObj!=null) {
        BeanWrapper destWrapper = new BeanWrapperImpl(destination);
        String subObjName = sourceProperty.getName();
        PropertyDescriptor destProperty = destWrapper.getPropertyDescriptor(subObjName);
        Class<?> propertyType = destProperty.getReadMethod().getReturnType();
        Object subObjCopy = propertyType.getConstructor().newInstance();
        doTransform(subObjCopy, subObj);
        destProperty.getWriteMethod().invoke(destination, subObjCopy);
    }
}
最终字符串TARGET\u PACKAGE=“com.thirdpartyguys.api”;
公共对象点传输(对象目标、对象源){
/*
*这将复制同一数据类型的所有属性,其中包含getter方法
*源和目标中的setter方法
*/
复制属性(源、目标);
BeanRapper sourceWrapper=新的BeanRapperImpl(源);
对于(PropertyDescriptor p:sourceWrapper.getPropertyDescriptors()){
/*
*引用其他架构对象的属性在结构上相同,但具有
*不同的包。我们需要分别复制这些包
*/
if(p.getPropertyType().getPackage().getName().StartWith(TARGET_PACKAGE)){
试一试{
公共财产副本(目的地、来源、p);
}捕获(例外e){
抛出新的RuntimeException(“创建数据的致命错误”,e);
}
}
/*
*引用列表的属性不会根据ApacheCXF创建setter
*我们必须调用get方法和addAll()
*/
else if(Collection.class.isAssignableFrom(p.getPropertyType())){
试一试{
收集副本(目的地、来源、p);
}捕获(例外e){
抛出新的RuntimeException(“创建数据的致命错误”,e);
}
}
}
返回目的地;
}
私有void collectionCopy(对象目标、对象源、PropertyDescriptor sourceProperty)引发异常{
BeanRapper destWrapper=新的BeanRapperImpl(目的地);
PropertyDescriptor destProperty=destWrapper.getPropertyDescriptor(sourceProperty.getName());
集合sourceCollection=(集合)sourceProperty.getReadMethod().invoke(源);
集合destCollection=(集合)destProperty.getReadMethod().invoke(目标);
destCollection.addAll(sourceCollection);
}
私有void commonPropertyCopy(对象目标、对象源、PropertyDescriptor sourceProperty)引发异常{
if(sourceProperty.getPropertyType().isEnum()){
实例化eNum(目标、源、sourceProperty);
}
否则{
实例化对象(目标、源、源属性);
}
}
私有void instanceEnum(对象目标、对象源、PropertyDescriptor sourceProperty)引发异常{
BeanRapper destWrapper=新的BeanRapperImpl(目的地);
Enum sourceEnum=(Enum)sourceProperty.getReadMethod().invoke(源);
PropertyDescriptor destProperty=destWrapper.getPropertyDescriptor(sourceProperty.getName());
Object enumValue=Enum.valueOf(destProperty.getPropertyType().asSubclass(Enum.class),sourceEnum.name());
destProperty.getWriteMethod().invoke(目标,枚举值);
}
私有void实例化对象(对象目标、对象源、PropertyDescriptor sourceProperty)引发异常{
Object subObj=sourceProperty.getReadMethod().invoke(源);
if(subObj!=null){
BeanRapper destWrapper=新的BeanRapperImpl(目的地);
字符串subObjName=sourceProperty.getName();
PropertyDescriptor destProperty=destWrapper.getPropertyDescriptor(subObjName);
类propertyType=destProperty.getReadMethod().getReturnType();
Object subObjCopy=propertyType.getConstructor().newInstance();
数据转换(subObj复制,subObj);
destProperty.getWriteMethod().invoke(目标,子对象副本);
}
}
InstanceObject用于从不同的包创建“相同”对象的新实例。这也适用于枚举类型,并且需要自己的方法,因此需要实现InstanceEnum。最后,默认的CXF实现没有为列表提供setter方法。我们在collectionCopy中处理这种情况