Cách để sao chép getters / setters cho các thuộc tính công cộng trong POJO


9

Chúng tôi có POJO được tạo tự động với ~ 60 thuộc tính. Điều này được tạo ra với avro 1.4, không bao gồm getters / setters.

Một thư viện mà chúng tôi sử dụng để cung cấp các phép biến đổi đơn giản giữa các đối tượng yêu cầu các phương thức giống như getter / setter để hoạt động đúng.

Có cách nào để sao chép getters / setters mà không phải ghi đè thủ công POJO và tạo tất cả các getters / setters bằng tay không?

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 ... };
}

mong muốn là viết mã giống như:

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");

Câu trả lời:


7

Ví dụ, bạn có thể cố gắng tạo các hạt proxy một cách linh hoạt bằng cách sử dụng BitBuddy: https://bytebuddy.net/

Mẫu dưới đây cho thấy cách ủy quyền một trường thuộc tính của một phương thức. Lưu ý rằng đây chỉ là một mẫu và rất có thể bạn có thể phải bọc nó và thêm một số động bằng cách sử dụng phản xạ, nhưng tôi nghĩ đó là một tùy chọn khá thú vị nếu bạn muốn tự động mở rộng mã.

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 cung cấp các chú thích @Getter và @Setter có thể được sử dụng ở cấp độ lớp để tạo các phương thức getter và setter tự động.

Lombok cũng có khả năng tạo ra các phương thức bằng và mã băm.

Hoặc bạn có thể sử dụng @Datađó là theo trang web lombok:

@Data Tất cả cùng nhau ngay bây giờ: Một lối tắt cho @ToString, @EqualsAndHashCode, @Getter trên tất cả các trường, @Setter trên tất cả các trường không phải là cuối cùng và @RequiredArgsConstructor!

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

1
Lombok rất dễ sử dụng và nhanh chóng để thiết lập. Đây là một giải pháp tốt.
Hayes Roach

Tôi nghĩ rằng rút gọn là việc thực hiện dễ dàng, sẽ giải quyết vấn đề và cũng cung cấp cho bạn khả năng đọc cao
leonardo rey

4

Đưa ra các ràng buộc của bạn, tôi sẽ thêm một bước tạo mã khác. Cách triển khai chính xác tùy thuộc vào hệ thống xây dựng của bạn (Maven / Gradle / cái gì khác), nhưng JavaParser hoặc Roaster sẽ cho phép bạn phân tích BigGeneratedPojo.javavà tạo một lớp con với getters / setters mong muốn và hệ thống xây dựng sẽ tự động cập nhật nếu BigGeneratedPojothay đổi.


1

Các IDE như Eclipse và STS cung cấp tùy chọn để thêm các phương thức getters / setters. chúng ta có thể sử dụng các tùy chọn đó để tạo các phương thức setters / getters


Vấn đề không phải là viết các phương pháp thực tế. Tôi biết làm thế nào để tạo ra những người nhanh chóng trong intellij. Vấn đề phát sinh trong thực tế BigGeneratedPojo là một tệp được tạo, vì vậy để thực sự thao tác với nó, tôi cần phải phân lớp nó và có một lớp bao bọc với các phương thức giả 120 (60 getters / setters) và là một cơn ác mộng phải duy trì.
Anthony

1
@Anthony Khi bạn mở tệp trong trình soạn thảo của IDE, việc tệp được tạo hoặc viết thủ công là không liên quan. Trong cả hai trường hợp, bạn có thể thêm các phương thức bằng một hành động. Chỉ khi bạn định tạo lại tệp, nó sẽ không hoạt động. Nhưng sau đó, việc có một lớp với 60 thuộc tính có khả năng thay đổi đã là một cơn ác mộng để duy trì thành công.
Holger

1

Tôi sẽ đề nghị sử dụng sự phản chiếu để lấy các trường công khai từ lớp của bạn và tạo các getters và setters bằng chương trình Java của riêng bạn như sau. Hãy xem xét các lớp sau đây là một ví dụ.

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());
    }
}

Mã được lấy từ đây - sửa đổi một chút để tránh không cần thiết System.out. Bạn có thể dễ dàng tạo một tập tin từ mainchức năng của bạn và đặt getters và setters của bạn ở đó.

Bạn có thể kiểm tra chương trình bằng cách chạy nó ở đây là tốt. Tôi hy vọng điều đó sẽ giúp.


1

Bạn có thể sử dụng Lombok. Là dễ sử dụng và thực hiện. Nó sẽ tạo getters và setter trong phần biên dịch tập tin. Class. Nó cũng giữ cho mã trông sạch hơn.

@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;
}

}

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.