POJO में सार्वजनिक संपत्तियों के लिए गेटर्स / सेटर को दोहराने का तरीका


9

हमारे पास एक POJO है जो ~ 60 गुणों के साथ ऑटो-जनरेट किया गया है। यह एवरो 1.4 के साथ उत्पन्न होता है, जिसमें गेटर्स / सेटर शामिल नहीं होते हैं।

एक पुस्तकालय जिसे हम वस्तुओं के बीच सरल परिवर्तन प्रदान करने के लिए उपयोग करते हैं, उसे ठीक से काम करने के लिए गेट्टर / सेटर जैसी विधियों की आवश्यकता होती है।

क्या मैन्युअल रूप से 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

प्रोजेक्ट लोम्बोक @Getter और @ सीटर एनोटेशन प्रदान करता है जिसका उपयोग स्वचालित रूप से गेट्टर और सेटर विधियों को उत्पन्न करने के लिए कक्षा स्तर पर किया जा सकता है।

लोम्बोक में भी बराबरी और हैशकोड विधियों को उत्पन्न करने की क्षमता है।

या आप @Dataलुम्बोक वेबसाइट के अनुसार उपयोग कर सकते हैं :

@Data सभी अब एक साथ: @ToString, @EqualsAndHashCode, @Getter पर सभी क्षेत्रों के लिए एक शॉर्टकट, सभी गैर-अंतिम फ़ील्ड्स पर @Setter, और @RequiredArgsConteror!

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

1
लोम्बोक उपयोग करने में आसान और सेटअप करने में तेज़ है। यह एक अच्छा उपाय है।
हेस रोच

मुझे लगता है कि एक शॉर्ट-कट के लिए आसान कार्यान्वयन है, समस्या को हल करेगा और आपको एक उच्च पठनीयता देगा
लियोनार्डो रे

4

आपकी बाधाओं को देखते हुए, मैं एक और कोड जनरेशन स्टेप जोड़ूंगा। इसे कैसे लागू किया जाए यह आपके बिल्ड सिस्टम (मावेन / ग्रेडल / कुछ और) पर निर्भर करता है, लेकिन JavaParser या Roaster आपको वांछित गेटर्स / सेटरों के साथ पार्सलBigGeneratedPojo.java बनाने और उपवर्ग बनाने की अनुमति देगा , और BigGeneratedPojoबदलाव होने पर बिल्ड सिस्टम को इसे अपडेट करना चाहिए ।


1

ग्रहण और एसटीएस की तरह आईडीई गेटर्स / सेटर के तरीकों को जोड़ने के लिए विकल्प प्रदान करते हैं। हम सेटर / गेटर्स मेथड बनाने के लिए उन विकल्पों का उपयोग कर सकते हैं


मुद्दा वास्तविक तरीकों को नहीं लिख रहा है। मुझे पता है कि इंटेलीज में उन लोगों को कैसे उत्पन्न किया जाए। समस्या इस तथ्य में पैदा होती है कि BigGeneratedPojo एक उत्पन्न फ़ाइल है, इसलिए वास्तव में इसे हेरफेर करने के लिए मुझे इसे उप-वर्ग करने की आवश्यकता होगी और एक आवरण वर्ग w / ~ 120 डमी विधियां (60 गेटर्स / सेटर) और बनाए रखने के लिए एक बुरा सपना है।
एंथनी

1
@Anthony जब आप फ़ाइल को IDE के संपादक में खोलते हैं, तो यह अप्रासंगिक है कि फ़ाइल जनरेट की गई है या मैन्युअल रूप से लिखी गई है। या तो मामले में, आप एक क्रिया के साथ तरीके जोड़ सकते हैं। जब आप फ़ाइल को फिर से जेनरेट करने की योजना बनाते हैं, तो यह काम नहीं करेगा। लेकिन फिर, 60 संभावित बदलते गुणों वाला एक वर्ग पहले से ही "बनाए रखने के लिए एक बुरा सपना" है।
होल्गर

1

मैं आपकी कक्षा से सार्वजनिक क्षेत्रों को प्राप्त करने के लिए प्रतिबिंब का उपयोग करने का सुझाव दूंगा और निम्नानुसार अपने स्वयं के जावा प्रोग्राम का उपयोग करके गेटर्स और सेटर बनाऊंगा। एक उदाहरण के रूप में निम्न वर्ग पर विचार करें।

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

}

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.