Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/392.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 通过反射将所有值从一个类中的字段复制到另一个类中_Java_Reflection - Fatal编程技术网

Java 通过反射将所有值从一个类中的字段复制到另一个类中

Java 通过反射将所有值从一个类中的字段复制到另一个类中,java,reflection,Java,Reflection,我有一个类,基本上是另一个类的副本 public class A { int a; String b; } public class CopyA { int a; String b; } 我所做的是将classA中的值放入CopyA中,然后通过webservice调用发送CopyA。现在我想创建一个反射方法,它基本上将所有相同的字段(按名称和类型)从classa复制到classCopyA 我该怎么做 到目前为止,这就是我所拥有的,但它不太管用。我想这里的问题是,我试图在我循环

我有一个类,基本上是另一个类的副本

public class A {
  int a;
  String b;
}

public class CopyA {
  int a;
  String b;
}
我所做的是将class
A
中的值放入
CopyA
中,然后通过webservice调用发送
CopyA
。现在我想创建一个反射方法,它基本上将所有相同的字段(按名称和类型)从class
a
复制到class
CopyA

我该怎么做

到目前为止,这就是我所拥有的,但它不太管用。我想这里的问题是,我试图在我循环通过的场上设置一个场

private <T extends Object, Y extends Object> void copyFields(T from, Y too) {

    Class<? extends Object> fromClass = from.getClass();
    Field[] fromFields = fromClass.getDeclaredFields();

    Class<? extends Object> tooClass = too.getClass();
    Field[] tooFields = tooClass.getDeclaredFields();

    if (fromFields != null && tooFields != null) {
        for (Field tooF : tooFields) {
            logger.debug("toofield name #0 and type #1", tooF.getName(), tooF.getType().toString());
            try {
                // Check if that fields exists in the other method
                Field fromF = fromClass.getDeclaredField(tooF.getName());
                if (fromF.getType().equals(tooF.getType())) {
                    tooF.set(tooF, fromF);
                }
            } catch (SecurityException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    }
private void copyFields(T from,Y也){
班级


2012年11月19日更新:现在也有了一个。

如果您不介意使用第三方库,来自Apache Commons的将非常容易地处理这个问题,使用
copyProperties(Object,Object)

tof.set()
的第一个参数应该是目标对象(
),而不是字段,第二个参数应该是值,而不是值来自的字段。(要获取值,需要调用
fromF.get()
——再次传入目标对象,在本例中是
from


大多数反射API都是这样工作的。您可以从类而不是实例中获取
字段
对象、
方法
对象等,以便使用它们(静态除外)您通常需要向它们传递一个实例。

BeanUtils只复制公共字段,速度有点慢。请使用getter和setter方法

public Object loadData (RideHotelsService object_a) throws Exception{

        Method[] gettersAndSetters = object_a.getClass().getMethods();

        for (int i = 0; i < gettersAndSetters.length; i++) {
                String methodName = gettersAndSetters[i].getName();
                try{
                  if(methodName.startsWith("get")){
                     this.getClass().getMethod(methodName.replaceFirst("get", "set") , gettersAndSetters[i].getReturnType() ).invoke(this, gettersAndSetters[i].invoke(object_a, null));
                        }else if(methodName.startsWith("is") ){
                            this.getClass().getMethod(methodName.replaceFirst("is", "set") ,  gettersAndSetters[i].getReturnType()  ).invoke(this, gettersAndSetters[i].invoke(object_a, null));
                        }

                }catch (NoSuchMethodException e) {
                    // TODO: handle exception
                }catch (IllegalArgumentException e) {
                    // TODO: handle exception
                }

        }

        return null;
    }
public Object loadData(RideHotelsService Object_a)引发异常{
方法[]gettersAndSetters=object_a.getClass().getMethods();
for(int i=0;i
我想你可以试试。它很好地支持bean到bean的转换。 它也很容易使用,您可以将它注入到spring应用程序中,或者在类路径中添加jar并完成它

有关您案例的示例:

 DozerMapper mapper = new DozerMapper();
A a= new A();
CopyA copyA = new CopyA();
a.set... // set fields of a.
mapper.map(a,copyOfA); // will copy all fields from a to copyA

Orika是一个简单而快速的bean映射框架,因为它是通过字节码生成的。它可以进行嵌套映射和不同名称的映射。有关更多详细信息,请 样例映射可能看起来很复杂,但对于复杂场景,它会很简单

MapperFactory factory = new DefaultMapperFactory.Builder().build();
mapperFactory.registerClassMap(mapperFactory.classMap(Book.class,BookDto.class).byDefault().toClassMap());
MapperFacade mapper = factory.getMapperFacade();
BookDto bookDto = mapperFacade.map(book, BookDto.class);

因为这个原因,我不想给另一个JAR文件添加依赖项,所以写了一些适合我需要的东西。我遵循fjorm的惯例,这意味着我通常可以访问的字段是公共的,我不需要费心编写setter和getter(在我看来,代码更容易管理,实际上更可读)

所以我写了一些适合我需要的东西(实际上并不难)(假设这个类有没有参数的公共构造函数),它可以被提取到实用类中

  public Effect copyUsingReflection() {
    Constructor constructorToUse = null;
    for (Constructor constructor : this.getClass().getConstructors()) {
      if (constructor.getParameterTypes().length == 0) {
        constructorToUse = constructor;
        constructorToUse.setAccessible(true);
      }
    }
    if (constructorToUse != null) {
      try {
        Effect copyOfEffect = (Effect) constructorToUse.newInstance();
        for (Field field : this.getClass().getFields()) {
          try {
            Object valueToCopy = field.get(this);
            //if it has field of the same type (Effect in this case), call the method to copy it recursively
            if (valueToCopy instanceof Effect) {
              valueToCopy = ((Effect) valueToCopy).copyUsingReflection();
            }
            //TODO add here other special types of fields, like Maps, Lists, etc.
            field.set(copyOfEffect, valueToCopy);
          } catch (IllegalArgumentException | IllegalAccessException ex) {
            Logger.getLogger(Effect.class.getName()).log(Level.SEVERE, null, ex);
          }
        }
        return copyOfEffect;
      } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
        Logger.getLogger(Effect.class.getName()).log(Level.SEVERE, null, ex);
      }
    }
    return null;
  }
  • 不使用BeanUtils或Apache Commons

  • 公共静态无效副本(T1
    origEntity,T2 destEntity)抛出非法访问异常,无此字段异常{
    Field[]fields=origEntity.getClass().getDeclaredFields();
    用于(字段:字段){
    集合(destEntity,field.get(origEntity));
    }
    }
    

  • 如果依赖项中有spring,也可以使用org.springframework.beans.BeanUtils

    我的解决方案:

    public static <T > void copyAllFields(T to, T from) {
            Class<T> clazz = (Class<T>) from.getClass();
            // OR:
            // Class<T> clazz = (Class<T>) to.getClass();
            List<Field> fields = getAllModelFields(clazz);
    
            if (fields != null) {
                for (Field field : fields) {
                    try {
                        field.setAccessible(true);
                        field.set(to,field.get(from));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
    public static List<Field> getAllModelFields(Class aClass) {
        List<Field> fields = new ArrayList<>();
        do {
            Collections.addAll(fields, aClass.getDeclaredFields());
            aClass = aClass.getSuperclass();
        } while (aClass != null);
        return fields;
    }
    
    公共静态void copyAllFields(T到,T从){
    类clazz=(类)from.getClass();
    //或:
    //类clazz=(类)到.getClass();
    列表字段=getAllModelFields(clazz);
    如果(字段!=null){
    用于(字段:字段){
    试一试{
    字段。setAccessible(true);
    field.set(to,field.get(from));
    }捕获(非法访问例外e){
    e、 printStackTrace();
    }
    }
    }
    }
    公共静态列表getAllModelFields(类aClass){
    列表字段=新的ArrayList();
    做{
    Collections.addAll(fields,aClass.getDeclaredFields());
    aClass=aClass.getSuperclass();
    }while(aClass!=null);
    返回字段;
    }
    
    为什么不使用gson库

    您只需将类A转换为json字符串。然后将jsonString转换为子类(CopyA)。使用以下代码:

    Gson gson= new Gson();
    String tmp = gson.toJson(a);
    CopyA myObject = gson.fromJson(tmp,CopyA.class);
    

    Spring有一个内置的
    BeanUtils.copyProperties
    方法。但是它不适用于没有getter/setter的类。JSON序列化/反序列化可以是复制字段的另一个选项。Jackson可以用于此目的。如果在大多数情况下使用Spring,Jackson已经在依赖项列表中

    ObjectMapper mapper=new ObjectMapper().configure(在未知属性上反序列化feature.FAIL,false);
    Clazz copyObject=mapper.readValue(mapper.writeValueAsString(sourceObject),Clazz.class);
    
    这是一个行之有效的解决方案。您可以控制类层次结构中映射的深度

    public class FieldMapper {
    
        public static void copy(Object from, Object to) throws Exception {
            FieldMapper.copy(from, to, Object.class);
        }
    
        public static void copy(Object from, Object to, Class depth) throws Exception {
            Class fromClass = from.getClass();
            Class toClass = to.getClass();
            List<Field> fromFields = collectFields(fromClass, depth);
            List<Field> toFields = collectFields(toClass, depth);
            Field target;
            for (Field source : fromFields) {
                if ((target = findAndRemove(source, toFields)) != null) {
                    target.set(to, source.get(from));
                }
            }
        }
    
        private static List<Field> collectFields(Class c, Class depth) {
            List<Field> accessibleFields = new ArrayList<>();
            do {
                int modifiers;
                for (Field field : c.getDeclaredFields()) {
                    modifiers = field.getModifiers();
                    if (!Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers)) {
                        accessibleFields.add(field);
                    }
                }
                c = c.getSuperclass();
            } while (c != null && c != depth);
            return accessibleFields;
        }
    
        private static Field findAndRemove(Field field, List<Field> fields) {
            Field actual;
            for (Iterator<Field> i = fields.iterator(); i.hasNext();) {
                actual = i.next();
                if (field.getName().equals(actual.getName())
                    && field.getType().equals(actual.getType())) {
                    i.remove();
                    return actual;
                }
            }
            return null;
        }
    }
    
    公共类字段映射器{
    公共静态无效副本(对象从、对象到)引发异常{
    FieldMapper.copy(from、to、Object.class);
    }
    公共图书馆
    
    public class FieldMapper {
    
        public static void copy(Object from, Object to) throws Exception {
            FieldMapper.copy(from, to, Object.class);
        }
    
        public static void copy(Object from, Object to, Class depth) throws Exception {
            Class fromClass = from.getClass();
            Class toClass = to.getClass();
            List<Field> fromFields = collectFields(fromClass, depth);
            List<Field> toFields = collectFields(toClass, depth);
            Field target;
            for (Field source : fromFields) {
                if ((target = findAndRemove(source, toFields)) != null) {
                    target.set(to, source.get(from));
                }
            }
        }
    
        private static List<Field> collectFields(Class c, Class depth) {
            List<Field> accessibleFields = new ArrayList<>();
            do {
                int modifiers;
                for (Field field : c.getDeclaredFields()) {
                    modifiers = field.getModifiers();
                    if (!Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers)) {
                        accessibleFields.add(field);
                    }
                }
                c = c.getSuperclass();
            } while (c != null && c != depth);
            return accessibleFields;
        }
    
        private static Field findAndRemove(Field field, List<Field> fields) {
            Field actual;
            for (Iterator<Field> i = fields.iterator(); i.hasNext();) {
                actual = i.next();
                if (field.getName().equals(actual.getName())
                    && field.getType().equals(actual.getType())) {
                    i.remove();
                    return actual;
                }
            }
            return null;
        }
    }
    
     object FieldMapper {
    
    fun <T:Any> copy(to: T, from: T) {
        try {
            val fromClass = from.javaClass
    
            val fromFields = getAllFields(fromClass)
    
            fromFields?.let {
                for (field in fromFields) {
                    try {
                        field.isAccessible = true
                        field.set(to, field.get(from))
                    } catch (e: IllegalAccessException) {
                        e.printStackTrace()
                    }
    
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    
    }
    
    private fun getAllFields(paramClass: Class<*>): List<Field> {
    
        var theClass:Class<*>? = paramClass
        val fields = ArrayList<Field>()
        try {
            while (theClass != null) {
                Collections.addAll(fields, *theClass?.declaredFields)
                theClass = theClass?.superclass
            }
        }catch (e:Exception){
            e.printStackTrace()
        }
    
        return fields
    }
    
    static public <X extends Object> X copy(X object, String... skipFields) {
            Constructor constructorToUse = null;
            for (Constructor constructor : object.getClass().getConstructors()) {
                if (constructor.getParameterTypes().length == 0) {
                    constructorToUse = constructor;
                    constructorToUse.setAccessible(true);
                    break;
                }
            }
            if (constructorToUse == null) {
                throw new IllegalStateException(object + " must have a zero arg constructor in order to be copied");
            }
            X copy;
            try {
                copy = (X) constructorToUse.newInstance();
    
                for (Field field : FieldUtils.getAllFields(object.getClass())) {
                    if (Modifier.isStatic(field.getModifiers())) {
                        continue;
                    }
    
                    //Avoid the fields that you don't want to copy. Note, if you pass in "id", it will skip any field with "id" in it. So be careful.
                    if (StringUtils.containsAny(field.getName(), skipFields)) {
                        continue;
                    }
    
                    field.setAccessible(true);
    
                    Object valueToCopy = field.get(object);
                    //TODO add here other special types of fields, like Maps, Lists, etc.
                    field.set(copy, valueToCopy);
    
                }
    
            } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                    | InvocationTargetException e) {
                throw new IllegalStateException("Could not copy " + object, e);
            }
            return copy;
    }
    
        public <T1 extends Object, T2 extends Object> void copy(T1 origEntity, T2 destEntity) {
            DozerBeanMapper mapper = new DozerBeanMapper();
            mapper.map(origEntity,destEntity);
        }
    
     <dependency>
                <groupId>net.sf.dozer</groupId>
                <artifactId>dozer</artifactId>
                <version>5.4.0</version>
            </dependency>
    
    public static <T> void copyAvalableFields(@NotNull T source, @NotNull T target) throws IllegalAccessException {
        Field[] fields = source.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (!Modifier.isStatic(field.getModifiers())
                    && !Modifier.isFinal(field.getModifiers())) {
                field.set(target, field.get(source));
            }
        }
    }