วิธีการทำซ้ำ getters / setters สำหรับคุณสมบัติสาธารณะใน POJO


9

เรามี POJO ที่สร้างขึ้นโดยอัตโนมัติด้วยคุณสมบัติ ~ 60 สิ่งนี้สร้างขึ้นด้วย avro 1.4 ซึ่งไม่รวม getters / setters

ไลบรารีที่เราใช้เพื่อให้การแปลงอย่างง่ายระหว่างวัตถุต้องใช้วิธีเหมือน getter / setter เพื่อให้ทำงานได้อย่างถูกต้อง

มีวิธีการทำซ้ำ getters / setters โดยไม่ต้องแทนที่ POJO ด้วยตนเองและสร้าง getters / setters ทั้งหมดด้วยตนเองหรือไม่

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

คุณสามารถลองสร้าง proxy beans ได้แบบไดนามิกโดยใช้ 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

โครงการลอมบอกให้คำอธิบายประกอบ @Getter และ @Setter ซึ่งสามารถใช้ในระดับชั้นเรียนเพื่อสร้างวิธี getter และ setter โดยอัตโนมัติ

ลอมบอกยังมีความสามารถในการสร้างวิธีการที่เท่าเทียมและแฮชโค้ด

หรือคุณสามารถใช้@Dataซึ่งเป็นไปตามเว็บไซต์ lombok:

@Data ทั้งหมดเข้าด้วยกันตอนนี้: ทางลัดสำหรับ @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และสร้างคลาสย่อยด้วย getters / setters ที่ต้องการและระบบ build ควรอัพเดตโดยอัตโนมัติหากมีBigGeneratedPojoการเปลี่ยนแปลง


1

IDEs เช่น Eclipse และ STS ให้ตัวเลือกในการเพิ่มเมธอด getters / setters เราสามารถใช้ตัวเลือกเหล่านั้นเพื่อสร้างเมธอด setters / getters


ปัญหาไม่ได้เขียนวิธีการจริง ฉันรู้วิธีสร้างผู้ที่อยู่ใน Intellij อย่างรวดเร็ว ปัญหาเกิดขึ้นในความจริงที่ว่าBigGeneratedPojo เป็นไฟล์ที่สร้างขึ้นดังนั้นเพื่อที่จะจัดการกับมันฉันจะต้องซับคลาสมันและมีคลาส wrapper คลาส w / ~ 120 วิธีการจำลอง (60 getters / setters) และเป็นฝันร้ายที่จะรักษา
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ฟังก์ชั่นของคุณและวาง getters และ setters ของคุณไว้ที่นั่น

คุณสามารถตรวจสอบโปรแกรมได้ด้วยการรันที่นี่เช่นกัน ฉันหวังว่าจะช่วย


1

คุณสามารถใช้ลอมบอก ใช้งานง่ายและใช้งานง่าย มันจะสร้าง getters และ setter ในการรวบรวมโพสต์ไฟล์. class นอกจากนี้ยังทำให้โค้ดดูสะอาดตา

@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.