কোনও ব্যক্তিগত পদ্ধতি চাওয়ার কোনও উপায়?


146

আমার কাছে একটি ক্লাস রয়েছে যা Objectঅন্য ক্লাসে এস ফেরত দেওয়ার জন্য এক্সএমএল এবং প্রতিবিম্ব ব্যবহার করে।

সাধারণত এই বস্তুগুলি একটি বাহ্যিক বস্তুর সাব ক্ষেত্র, তবে মাঝেমধ্যে এটি এমন কিছু যা আমি ফ্লাইতে উত্পন্ন করতে চাই। আমি এরকম কিছু চেষ্টা করেছি কিন্তু লাভ হয়নি। আমি বিশ্বাস করি এটি কারণ জাভা আপনাকে privateপ্রতিবিম্বের জন্য পদ্ধতিগুলি অ্যাক্সেস করতে দেয় না ।

Element node = outerNode.item(0);
String methodName = node.getAttribute("method");
String objectName = node.getAttribute("object");

if ("SomeObject".equals(objectName))
    object = someObject;
else
    object = this;

method = object.getClass().getMethod(methodName, (Class[]) null);

প্রদত্ত পদ্ধতিটি যদি হয় তবে privateএটি ক NoSuchMethodException। আমি পদ্ধতিটি তৈরি করে public, বা এটি থেকে উত্পন্ন করার জন্য অন্য কোনও শ্রেণি তৈরি করে সমাধান করতে পারি ।

দীর্ঘ গল্প সংক্ষেপে, আমি কেবল ভাবছিলাম যে privateপ্রতিবিম্বের মাধ্যমে কোনও পদ্ধতি অ্যাক্সেস করার কোনও উপায় আছে কিনা ।

উত্তর:


303

আপনি প্রতিফলনের সাথে ব্যক্তিগত পদ্ধতিতে আবেদন করতে পারেন। পোস্ট করা কোডের শেষ বিটটি পরিবর্তন করা:

Method method = object.getClass().getDeclaredMethod(methodName);
method.setAccessible(true);
Object r = method.invoke(object);

সেখানে বেশ কয়েকটা ক্যাভেট রয়েছে। প্রথমত, getDeclaredMethodকেবলমাত্র বর্তমানের মধ্যে ঘোষিত পদ্ধতিটি Classপাওয়া যাবে, সুপারটাইপগুলি থেকে উত্তরাধিকার সূত্রে প্রাপ্ত নয়। সুতরাং, প্রয়োজনে কংক্রিট শ্রেণীর শ্রেণিবিন্যাসকে অতিক্রম করুন। দ্বিতীয়ত, একটি পদ্ধতি SecurityManagerব্যবহার রোধ করতে পারে setAccessible। সুতরাং, এটি PrivilegedAction(ব্যবহার AccessControllerবা Subject) হিসাবে চালানোর প্রয়োজন হতে পারে ।


2
অতীতে যখন আমি এটি করেছি, আমি পদ্ধতিটি কল করার পরেও মেথড.সেটএ্যাক্সেসিবল (মিথ্যা) বলেছি, তবে এটি প্রয়োজনীয় কিনা এবং আমার কোনও ধারণা নেই।
shsteimer

16
না, যখন আপনি অ্যাক্সেসযোগ্যতা সেট করেন, এটি কেবলমাত্র সেই উদাহরণটিতে প্রযোজ্য। যতক্ষণ আপনি এই নির্দিষ্ট পদ্ধতি অবজেক্টটিকে আপনার নিয়ন্ত্রণ থেকে বাঁচতে না দেন ততক্ষণ এটি নিরাপদ।
এরিকসন

6
তাহলে কি প্রাইভেট পদ্ধতি থাকার কথা যদি তাদের শ্রেণীর বাইরে থেকে ডেকে আনা যায়?
পিটার আজতাই

2
এছাড়াও নিশ্চিত করুন যে আপনি ন্যায়বিচারের getDeclaredMethod()পরিবর্তে কল করেছেন getMethod()- এটি ব্যক্তিগত পদ্ধতির জন্য কাজ করবে না।
এর্কসেন

1
@ পিটারআজতাই দেরিতে সাড়া পাওয়ার জন্য দুঃখিত, তবে এটিকে এভাবে ভাবুন: আজকাল বেশিরভাগ লোকেরা তাদের দরজা লক করে রাখেন যদিও তারা জানেন যে লকটি তুচ্ছভাবে ভেঙে বা সম্পূর্ণভাবে সাজানো যেতে পারে। কেন? কারণ এটি বেশিরভাগ সৎ লোককে সৎ রাখতে সহায়তা করে। আপনি privateঅ্যাক্সেসের অনুরূপ ভূমিকা পালন করার কথা ভাবতে পারেন ।
এরিকসন

34

getDeclaredMethod()একটি ব্যক্তিগত পদ্ধতি অবজেক্ট পেতে ব্যবহার করুন এবং তারপরে method.setAccessible()এটি কল করার অনুমতি দেওয়ার জন্য ব্যবহার করুন ।


আমার নিজের উদাহরণে ( স্ট্যাকওভারফ্লো.com/ a/ 15612040 / 257233 ) আমি java.lang.StackOverflowErrorকল না দিলে আমি পাই setAccessible(true)
রবার্ট মার্ক ব্রাম

25

যদি পদ্ধতিটি অ-আদিম উপাত্তের প্রকারটি গ্রহণ করে তবে নীচের পদ্ধতিটি যে কোনও শ্রেণীর একটি ব্যক্তিগত পদ্ধতি চাওয়ার জন্য ব্যবহার করা যেতে পারে:

public static Object genericInvokeMethod(Object obj, String methodName,
            Object... params) {
        int paramCount = params.length;
        Method method;
        Object requiredObj = null;
        Class<?>[] classArray = new Class<?>[paramCount];
        for (int i = 0; i < paramCount; i++) {
            classArray[i] = params[i].getClass();
        }
        try {
            method = obj.getClass().getDeclaredMethod(methodName, classArray);
            method.setAccessible(true);
            requiredObj = method.invoke(obj, params);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        return requiredObj;
    }

গৃহীত প্যারামিটারগুলি হ'ল অবজেক্ট, মেথডনেম এবং পরামিতি। উদাহরণ স্বরূপ

public class Test {
private String concatString(String a, String b) {
    return (a+b);
}
}

পদ্ধতির কনক্যাটস্ট্রিং হিসাবে আমন্ত্রণ জানানো যেতে পারে

Test t = new Test();
    String str = (String) genericInvokeMethod(t, "concatString", "Hello", "Mr.x");

7
প্যারামকাউন্ট কেন দরকার? আপনি কি কেবল প্যারাম.লেনথ ব্যবহার করতে পারবেন না ?
সাদ মালিক

7

আপনি এটি বসন্তের রিফ্লেকশনস্টেস্টিলগুলি ব্যবহার করে করতে পারেন ( org.springframework.test.util.ReflectionTestUtils )

ReflectionTestUtils.invokeMethod(instantiatedObject,"methodName",argument);

উদাহরণ: আপনার যদি একটি ব্যক্তিগত পদ্ধতি সহ ক্লাস থাকে square(int x)

Calculator calculator = new Calculator();
ReflectionTestUtils.invokeMethod(calculator,"square",10);

মূল বসন্তে আরও সীমিত প্রতিচ্ছবি রয়েছে।
থান্ডারফোর্জ

3

আমি প্রতিবিম্বের মাধ্যমে সম্পাদন সুরক্ষিত পদ্ধতিগুলির জন্য সম্পূর্ণ কোড সরবরাহ করি। এটি জেনেরিকস, অটোবক্সেড প্যারাম এবং নাল মান সহ যে কোনও ধরণের প্যারাম সমর্থন করে

@SuppressWarnings("unchecked")
public static <T> T executeSuperMethod(Object instance, String methodName, Object... params) throws Exception {
    return executeMethod(instance.getClass().getSuperclass(), instance, methodName, params);
}

public static <T> T executeMethod(Object instance, String methodName, Object... params) throws Exception {
    return executeMethod(instance.getClass(), instance, methodName, params);
}

@SuppressWarnings("unchecked")
public static <T> T executeMethod(Class clazz, Object instance, String methodName, Object... params) throws Exception {

    Method[] allMethods = clazz.getDeclaredMethods();

    if (allMethods != null && allMethods.length > 0) {

        Class[] paramClasses = Arrays.stream(params).map(p -> p != null ? p.getClass() : null).toArray(Class[]::new);

        for (Method method : allMethods) {
            String currentMethodName = method.getName();
            if (!currentMethodName.equals(methodName)) {
                continue;
            }
            Type[] pTypes = method.getParameterTypes();
            if (pTypes.length == paramClasses.length) {
                boolean goodMethod = true;
                int i = 0;
                for (Type pType : pTypes) {
                    if (!ClassUtils.isAssignable(paramClasses[i++], (Class<?>) pType)) {
                        goodMethod = false;
                        break;
                    }
                }
                if (goodMethod) {
                    method.setAccessible(true);
                    return (T) method.invoke(instance, params);
                }
            }
        }

        throw new MethodNotFoundException("There are no methods found with name " + methodName + " and params " +
            Arrays.toString(paramClasses));
    }

    throw new MethodNotFoundException("There are no methods found with name " + methodName);
}

অটোবক্সযুক্ত প্যারামগুলির সামঞ্জস্যতা পরীক্ষা করার জন্য পদ্ধতি অ্যাপাচি ক্লাস ইউটিস ব্যবহার করে


৯০০০০ বছরেরও বেশি বার দেখা এবং একটি স্বীকৃত উত্তর সহ 9 বছরের পুরানো প্রশ্নের উত্তর দেওয়ার একেবারেই অর্থ নেই। পরিবর্তে অনুত্তরিত প্রশ্নের উত্তর দিন।
অনুরাগ বৈশ্য

0

আরও একটি বৈকল্পিক খুব পাওয়ারফুল JOOR লাইব্রেরি https://github.com/jOOQ/jOOR ব্যবহার করছে

MyObject myObject = new MyObject()
on(myObject).get("privateField");  

এটি উত্তরাধিকারের স্তরক্রমের ক্ষেত্রে কংক্রিট শ্রেণি নির্দিষ্ট না করে চূড়ান্ত স্ট্যাটিক ধ্রুবকগুলির মতো যেকোন ক্ষেত্র পরিবর্তন করতে এবং ইয়েন সুরক্ষিত পদ্ধতিগুলিতে কল করার অনুমতি দেয়

<!-- https://mvnrepository.com/artifact/org.jooq/joor-java-8 -->
<dependency>
     <groupId>org.jooq</groupId>
     <artifactId>joor-java-8</artifactId>
     <version>0.9.7</version>
</dependency>

0

আপনি সরাসরি, টাইপ-নিরাপদ জাভা প্রতিবিম্বের জন্য ম্যানিফোল্ডের @ জেলব্রেক ব্যবহার করতে পারেন :

@Jailbreak Foo foo = new Foo();
foo.callMe();

public class Foo {
    private void callMe();
}

@Jailbreakএর শ্রেণিবিন্যাসের fooসমস্ত সদস্যের সরাসরি অ্যাক্সেসের জন্য সংকলকটিতে স্থানীয় চলকটি আনলক করে Foo

একইভাবে আপনি জেল ব্রেক () এক্সটেনশন পদ্ধতিটি এক-বন্ধ ব্যবহারের জন্য ব্যবহার করতে পারেন:

foo.jailbreak().callMe();

jailbreak()পদ্ধতির মাধ্যমে আপনি যে কোনও সদস্যের Fooশ্রেণিবিন্যাসের অ্যাক্সেস করতে পারবেন ।

উভয় ক্ষেত্রেই সংকলকটি আপনার জন্য টাইপ-সুরক্ষিত পদ্ধতি কলটি সমাধান করে, যেন কোনও পাবলিক পদ্ধতি, ম্যানিফোल्ड হুডের নিচে আপনার জন্য দক্ষ প্রতিবিম্ব কোড তৈরি করে।

বিকল্পভাবে, প্রকারটি যদি স্থিতিকরভাবে না জানা যায় তবে আপনি কোনও ইন্টারফেস সংজ্ঞায়িত করতে স্ট্রাকচারাল টাইপিং ব্যবহার করতে পারেন যা কোনও প্রকারের প্রয়োগটি ঘোষণা না করেই সন্তুষ্ট করতে পারে type এই কৌশলটি টাইপ-সুরক্ষা বজায় রাখে এবং প্রতিবিম্ব এবং প্রক্সি কোডের সাথে সম্পর্কিত কার্য সম্পাদন এবং পরিচয় সম্পর্কিত বিষয়গুলি এড়িয়ে চলে।

ম্যানিফোल्ड সম্পর্কে আরও আবিষ্কার করুন ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.