POJO의 퍼블릭 속성에 대한 게터 / 세터 복제 방법


9

~ 60 개의 속성으로 자동 생성 된 POJO가 있습니다. 이것은 게터 / 세터를 포함하지 않는 avro 1.4로 생성됩니다.

객체간에 간단한 변형을 제공하기 위해 사용하는 라이브러리는 제대로 작동하려면 getter / setter와 유사한 방법이 필요합니다.

POJO를 수동으로 재정의하지 않고 게터 / 세터를 복제하고 모든 게터 / 세터를 수동으로 만들 수있는 방법이 있습니까?

public class BigGeneratedPojo {
  public String firstField;
  public int secondField;
  ...
  public ComplexObject nthField;
}

public class OtherObject {
  private String reprOfFirstFieldFromOtherObject;
  private ComplexObject reprOfFirstFieldFromOtherObject;
  public String getReprOfFirstFieldFromOtherObject() { ... standard impl ... };
  public void setReprOfFirstFieldFromOtherObject() { ... standard impl ... };
}

원하는 것은 다음과 같은 코드를 작성하는 것입니다.

Mapper<BigGeneratedPojo, OtherObject> mapper = 
  MagicalMapperLibrary.mapperBuilder(BigGeneratedPojo.class, OtherObject.class)
    .from(BigGeneratedPojo::getFirstField).to(OtherObject::reprOfFirstFieldFromOtherObject)
    .build();

BigGeneratedPojo pojo = new BigGeneratedPojo();
pojo.firstField = "test";

OtherObject mappedOtherObj = mapper.map(pojo);

assertEquals(mappedOtherObj.getReprOfFirstFieldFromOtherObject(), "test");

답변:


7

BitBuddy를 사용하여 프록시 빈을 동적으로 생성하려고 시도 할 수 있습니다. https://bytebuddy.net/

아래 샘플은 메소드의 특성 필드를 프록시하는 방법을 보여줍니다. 이것은 샘플 일 뿐이며, 아마도 랩을 사용하여 리플렉션을 사용하여 동적을 추가해야 할 수도 있지만 코드를 동적으로 확장하려는 경우 상당히 흥미로운 옵션이라고 생각합니다.

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.jar.asm.Opcodes;
import org.apache.commons.beanutils.BeanUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

public class M1 {

    public static class PojoBase {
        int property;
        String strProp;
    }



    public static class Intereptor {

        private final String fieldName;
        private final PojoBase pojo;
        public Intereptor(PojoBase pojo, String fieldName) {
            this.pojo = pojo;
            this.fieldName = fieldName;
        }
        @RuntimeType
        public Object intercept(@RuntimeType Object value) throws NoSuchFieldException, IllegalAccessException {

            Field field = pojo.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(pojo, value);
            return value;
        }
    }



    public static void main(String... args) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
            PojoBase origBean = new PojoBase();
            PojoBase destBean = new PojoBase();

            origBean.property = 555666;
            origBean.strProp = "FooBar";

        DynamicType.Builder<Object> stub = new ByteBuddy()
            .subclass(Object.class);

        DynamicType.Builder.MethodDefinition.ReceiverTypeDefinition<Object> dynamic = stub.defineMethod("getProperty", Integer.TYPE, Opcodes.ACC_PUBLIC).intercept(FixedValue.value(origBean.property))
                .defineMethod("setProperty", Void.TYPE, Opcodes.ACC_PUBLIC).withParameters(Integer.TYPE).intercept(MethodDelegation.to(new Intereptor(destBean, "property")))
                .defineMethod("getStrProp", String.class, Opcodes.ACC_PUBLIC).intercept(FixedValue.value(origBean.strProp))
                .defineMethod("setStrProp", Void.TYPE, Opcodes.ACC_PUBLIC).withParameters(String.class).intercept(MethodDelegation.to(new Intereptor(destBean, "strProp")));

        Class<?> dynamicType =     dynamic.make()
                .load(M1.class.getClassLoader())
                .getLoaded();


            Object readerObject = dynamicType.newInstance();
            Object writterObject = dynamicType.newInstance();


            BeanUtils.copyProperties(readerObject, writterObject);
            System.out.println("Out property:" + destBean.property);
            System.out.println("Out strProp:" + destBean.property);
    }



}

10

Project Lombok 은 클래스 수준에서 getter 및 setter 메서드를 자동으로 생성하는 데 사용할 수있는 @Getter 및 @Setter 주석을 제공합니다.

롬복은 또한 equals 및 hashcode 메소드를 생성하는 기능을 가지고 있습니다.

또는 @Datalombok 웹 사이트에 따라 사용할 수 있습니다 :

@Data All together now : @ToString, @EqualsAndHashCode, 모든 필드에서 @Getter, 모든 비 최종 필드에서 @Setter 및 @RequiredArgsConstructor에 대한 바로 가기!

@Data
public class BigGeneratedPojo {
  public String firstField;
  public int secondField;
  ...
  public ComplexObject nthField;
}

1
롬복은 사용하기 쉽고 설치가 빠릅니다. 이것은 좋은 해결책입니다.
Hayes Roach

저는 바로 가기가 쉬운 구현이고 문제를 해결하고 높은 가독성을 제공한다고 생각합니다.
leonardo rey

4

제약 조건이 주어지면 다른 코드 생성 단계를 추가합니다. 그것을 구현하는 방법은 빌드 시스템 (Maven / Gradle / 다른 것)에 정확히 달려 있지만 JavaParser 또는 Roaster 를 사용하면 BigGeneratedPojo.java원하는 getter / setter로 서브 클래스 를 구문 분석 하고 만들 수 있으며 BigGeneratedPojo변경 되면 빌드 시스템이 자동으로 업데이트해야합니다 .


1

Eclipse 및 STS와 같은 IDE는 게터 / 세터 메소드를 추가하는 옵션을 제공합니다. 해당 옵션을 사용하여 setter / getters 메소드를 작성할 수 있습니다


문제는 실제 방법을 쓰지 않습니다. 나는 intellij에서 신속하게 생성하는 방법을 알고 있습니다. 문제 BigGeneratedPojo 는 생성 된 파일 이라는 사실에서 발생하므로 실제로 파일을 조작하려면 하위 클래스를 작성하고 ~ 120 개의 더미 메소드 (60 getter / setter) / wrapper 클래스가 있어야하며 유지 해야하는 악몽입니다.
Anthony

1
@Anthony IDE 편집기에서 파일을 열 때 파일이 수동으로 생성되었는지 또는 작성되었는지는 중요하지 않습니다. 두 경우 모두 단일 조치로 메소드를 추가 할 수 있습니다. 파일을 다시 생성하려는 경우에만 작동하지 않습니다. 그러나 60 개의 잠재적으로 변화하는 속성을 가진 클래스를 갖는 것은 이미“유지하기에 악몽”입니다.
Holger

1

리플렉션을 사용하여 클래스에서 공개 필드를 가져오고 다음과 같이 자신의 Java 프로그램을 사용하여 게터 및 세터를 만드는 것이 좋습니다. 다음 클래스를 예로 들어 보겠습니다.

import java.lang.reflect.Field;
import java.util.Arrays;

class TestClass {

    private int value;
    private String name;
    private boolean flag;
}

public class GetterSetterGenerator {

    public static void main(String[] args) {
        try {
            GetterSetterGenerator gt = new GetterSetterGenerator();
            StringBuffer sb = new StringBuffer();

            Class<?> c = Class.forName("TestClass");
            // Getting fields of the class
            Field[] fields = c.getDeclaredFields();

            for (Field f : fields) {
                String fieldName = f.getName();
                String fieldType = f.getType().getSimpleName();

                gt.createSetter(fieldName, fieldType, sb);
                gt.createGetter(fieldName, fieldType, sb);
            }
            System.out.println("" + sb.toString());

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private void createSetter(String fieldName, String fieldType, StringBuffer setter) {
        setter.append("public void").append(" set");
        setter.append(getFieldName(fieldName));
        setter.append("(" + fieldType + " " + fieldName + ") {");
        setter.append("\n\t this." + fieldName + " = " + fieldName + ";");
        setter.append("\n" + "}" + "\n");
    }

    private void createGetter(String fieldName, String fieldType, StringBuffer getter) {
        // for boolean field method starts with "is" otherwise with "get"
        getter.append("public " + fieldType).append((fieldType.equals("boolean") ? " is" : " get") + getFieldName(fieldName) + " () { ");
        getter.append("\n\treturn " + fieldName + ";");
        getter.append("\n" + "}" + "\n");
    }

    private String getFieldName(String fieldName) {
        return fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1, fieldName.length());
    }
}

이 코드는 불필요한 수정을 피하기 위해 여기에서 약간 수정되었습니다 System.out. main함수 에서 파일을 쉽게 만들고 게터와 세터를 거기에 넣을 수 있습니다.

여기 에서 프로그램을 실행하여 확인할 수도 있습니다. 도움이 되길 바랍니다.


1

롬복을 사용할 수 있습니다. 사용하고 구현하기 쉽습니다. 컴파일 후 .class 파일에서 getter 및 setter를 작성합니다. 또한 코드를 더 깨끗하게 유지합니다.

@Getter @Setter @NoArgsConstructor
public class User implements Serializable {
 private @Id Long id;

private String firstName;
private String lastName;
private int age;

public User(String firstName, String lastName, int age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
}

}

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.