জাভা
String getParamName(String param) throws Exception {
StackTraceElement[] strace = new Exception().getStackTrace();
String methodName = strace[0].getMethodName();
int lineNum = strace[1].getLineNumber();
String className = strace[1].getClassName().replaceAll(".{5}$", "");
String classPath = Class.forName(className).getProtectionDomain().getCodeSource().getLocation().getPath() + className + ".class";
StringWriter javapOut = new StringWriter();
com.sun.tools.javap.Main.run(new String[] {"-l", "-c", classPath}, new PrintWriter(javapOut));
List<String> javapLines = Arrays.asList(javapOut.toString().split("\\r?\\n"));
int byteCodeStart = -1;
Map<Integer, Integer> byteCodePointerToJavaPLine = new HashMap<Integer, Integer>();
Pattern byteCodeIndexPattern = Pattern.compile("^\\s*(\\d+): ");
for (int n = 0;n < javapLines.size();n++) {
String javapLine = javapLines.get(n);
if (byteCodeStart > -1 && (javapLine == null || "".equals(javapLine))) {
break;
}
Matcher byteCodeIndexMatcher = byteCodeIndexPattern.matcher(javapLine);
if (byteCodeIndexMatcher.find()) {
byteCodePointerToJavaPLine.put(Integer.parseInt(byteCodeIndexMatcher.group(1)), n);
} else if (javapLine.contains("line " + lineNum + ":")) {
byteCodeStart = Integer.parseInt(javapLine.substring(javapLine.indexOf(": ") + 2));
}
}
int varLoadIndex = -1;
int varTableIndex = -1;
for (int i = byteCodePointerToJavaPLine.get(byteCodeStart) + 1;i < javapLines.size();i++) {
if (varLoadIndex < 0 && javapLines.get(i).contains("Method " + methodName + ":")) {
varLoadIndex = i;
continue;
}
if (varLoadIndex > -1 && javapLines.get(i).contains("LocalVariableTable:")) {
varTableIndex = i;
break;
}
}
String loadLine = javapLines.get(varLoadIndex - 1).trim();
int varNumber;
try {
varNumber = Integer.parseInt(loadLine.substring(loadLine.indexOf("aload") + 6).trim());
} catch (NumberFormatException e) {
return null;
}
int j = varTableIndex + 2;
while(!"".equals(javapLines.get(j))) {
Matcher varName = Pattern.compile("\\s*" + varNumber + "\\s*([a-zA-Z_][a-zA-Z0-9_]*)").matcher(javapLines.get(j));
if (varName.find()) {
return varName.group(1);
}
j++;
}
return null;
}
এটি বর্তমানে কয়েকটি গোছা নিয়ে কাজ করে:
- এটি সংকলনের জন্য আপনি যদি কোনও আইডিই ব্যবহার করেন তবে এটি অ্যাডমিন হিসাবে চালিত না করা (অস্থায়ী শ্রেণীর ফাইলগুলি কোথায় সংরক্ষণ করা হয়েছে তার উপর নির্ভর করে) এটি কাজ করতে পারে না
- ব্যবহার করে আপনি কম্পাইল করতে হবে
javacসঙ্গে -gপতাকা। এটি সংকলিত শ্রেণীর ফাইলের স্থানীয় ভেরিয়েবলের নাম সহ সমস্ত ডিবাগিং তথ্য উত্পন্ন করে।
- এটি একটি অভ্যন্তরীণ জাভা এপিআই ব্যবহার করে
com.sun.tools.javapযা শ্রেণিবদ্ধের বাইটকোডকে পার্স করে এবং একটি মানব পাঠযোগ্য ফলাফল উত্পাদন করে। এই এপিআইটি কেবল জেডিকে গ্রন্থাগারগুলিতে অ্যাক্সেসযোগ্য তাই আপনাকে জেডিকে জাভা রানটাইম ব্যবহার করতে হবে বা আপনার ক্লাসপাথে টুলস.জার যুক্ত করতে হবে।
প্রোগ্রামটিতে পদ্ধতিটি একাধিকবার বলা হলেও এটি এখন কাজ করা উচিত। দুর্ভাগ্যক্রমে এটি এখনও কাজ করে না যদি আপনার একক লাইনে একাধিক অনুরোধ থাকে। (যা করে তার জন্য, নীচে দেখুন)
এটি অনলাইন চেষ্টা করুন!
ব্যাখ্যা
StackTraceElement[] strace = new Exception().getStackTrace();
String methodName = strace[0].getMethodName();
int lineNum = strace[1].getLineNumber();
String className = strace[1].getClassName().replaceAll(".{5}$", "");
String classPath = Class.forName(className).getProtectionDomain().getCodeSource().getLocation().getPath() + className + ".class";
এই বিভাগে আমরা কোন শ্রেণিতে রয়েছি এবং ফাংশনটির নামটি সম্পর্কে কিছু সাধারণ তথ্য পাওয়া যায়। এটি একটি ব্যতিক্রম তৈরি করে এবং স্ট্যাক ট্রেসের প্রথম 2 টি এন্ট্রি বিশ্লেষণ করে সম্পন্ন হয়।
java.lang.Exception
at E.getParamName(E.java:28)
at E.main(E.java:17)
প্রথম এন্ট্রিটি হ'ল রেখাটি যে ব্যতিক্রমটি নিক্ষেপ করা হয় যার উপরে আমরা পদ্ধতি নামটি ধরে ফেলতে পারি এবং দ্বিতীয় প্রবেশটি যেখানে ফাংশনটি ডেকে আনা হয়েছিল।
StringWriter javapOut = new StringWriter();
com.sun.tools.javap.Main.run(new String[] {"-l", "-c", classPath}, new PrintWriter(javapOut));
এই লাইনে আমরা জাভাকে এক্সিকিউটেবল কার্যকর করব যা জেডিকে সাথে আসে। এই প্রোগ্রামটি ক্লাস ফাইল (বাইটকোড) পার্স করে এবং একটি মানব-পঠনযোগ্য ফলাফল উপস্থাপন করে। আমরা এটি প্রাথমিক "পার্সিং" এর জন্য ব্যবহার করব।
List<String> javapLines = Arrays.asList(javapOut.toString().split("\\r?\\n"));
int byteCodeStart = -1;
Map<Integer, Integer> byteCodePointerToJavaPLine = new HashMap<Integer, Integer>();
Pattern byteCodeIndexPattern = Pattern.compile("^\\s*(\\d+): ");
for (int n = 0;n < javapLines.size();n++) {
String javapLine = javapLines.get(n);
if (byteCodeStart > -1 && (javapLine == null || "".equals(javapLine))) {
break;
}
Matcher byteCodeIndexMatcher = byteCodeIndexPattern.matcher(javapLine);
if (byteCodeIndexMatcher.find()) {
byteCodePointerToJavaPLine.put(Integer.parseInt(byteCodeIndexMatcher.group(1)), n);
} else if (javapLine.contains("line " + lineNum + ":")) {
byteCodeStart = Integer.parseInt(javapLine.substring(javapLine.indexOf(": ") + 2));
}
}
আমরা এখানে বেশ কয়েকটি ভিন্ন জিনিস করছি। প্রথমত, আমরা জাভ্যাপ আউটপুট লাইনটি লাইনে একটি তালিকার মধ্যে পড়ছি। দ্বিতীয়টি আমরা জাভ্যাপ লাইন সূচকে বাইকোড লাইন সূচকের মানচিত্র তৈরি করছি। এটি আমাদের পরবর্তী পদ্ধতিটি যা বিশ্লেষণ করতে চাইছে তা নির্ধারণ করতে সহায়তা করে। অবশেষে আমরা কোন বাইটোকড লাইন সূচকে আমরা সন্ধান করতে চাই তা নির্ধারণ করতে স্ট্যাক ট্রেস থেকে পরিচিত লাইন নম্বরটি ব্যবহার করছি।
int varLoadIndex = -1;
int varTableIndex = -1;
for (int i = byteCodePointerToJavaPLine.get(byteCodeStart) + 1;i < javapLines.size();i++) {
if (varLoadIndex < 0 && javapLines.get(i).contains("Method " + methodName + ":")) {
varLoadIndex = i;
continue;
}
if (varLoadIndex > -1 && javapLines.get(i).contains("LocalVariableTable:")) {
varTableIndex = i;
break;
}
}
আমাদের পদ্ধতিটি কোথায় ডাকা হচ্ছে এবং কোথায় স্থানীয় চলক সারণি শুরু হয় তা সন্ধান করতে এখানে আমরা জাভাপ লাইনের উপরে আরও একবার পুনরাবৃত্তি করছি। আমাদের সেই লাইনের দরকার যেখানে পদ্ধতিটি আহবান করা হয় কারণ লাইনে তার আগে ভেরিয়েবলটি লোড করার জন্য কল রয়েছে এবং চিহ্নিত করে কোন ভেরিয়েবলটি (সূচক অনুসারে) লোড করতে হবে। স্থানীয় পরিবর্তনীয় সারণী আমাদের যে সূচকটি ধরে নিয়েছিল তার উপর ভিত্তি করে ভেরিয়েবলের নামটি সন্ধান করতে সহায়তা করে।
String loadLine = javapLines.get(varLoadIndex - 1).trim();
int varNumber;
try {
varNumber = Integer.parseInt(loadLine.substring(loadLine.indexOf("aload") + 6).trim());
} catch (NumberFormatException e) {
return null;
}
এই অংশটি ভেরিয়েবল সূচক পেতে লোড কলকে পার্সিং করছে। এটি একটি ব্যতিক্রম ছুঁড়ে ফেলতে পারে যদি ফাংশনটি আসলে কোনও ভেরিয়েবলের সাথে না ডাকা হয় যাতে আমরা এখানে শূন্য ফিরে আসতে পারি।
int j = varTableIndex + 2;
while(!"".equals(javapLines.get(j))) {
Matcher varName = Pattern.compile("\\s*" + varNumber + "\\s*([a-zA-Z_][a-zA-Z0-9_]*)").matcher(javapLines.get(j));
if (varName.find()) {
return varName.group(1);
}
j++;
}
return null;
অবশেষে আমরা স্থানীয় পরিবর্তনশীল সারণীতে লাইনটি থেকে ভেরিয়েবলের নাম পার্স করি। যদি এটি না পাওয়া যায় তবে শূন্যস্থানটি ফিরুন যদিও আমি এরকম হওয়ার কোনও কারণ দেখিনি।
সবগুলোকে একত্রে রাখ
public static void main(java.lang.String[]);
Code:
...
18: getstatic #19 // Field java/lang/System.out:Ljava/io/PrintStream;
21: aload_1
22: aload_2
23: invokevirtual #25 // Method getParamName:(Ljava/lang/String;)Ljava/lang/String;
...
LineNumberTable:
...
line 17: 18
line 18: 29
line 19: 40
...
LocalVariableTable:
Start Length Slot Name Signature
0 83 0 args [Ljava/lang/String;
8 75 1 e LE;
11 72 2 str Ljava/lang/String;
14 69 3 str2 Ljava/lang/String;
18 65 4 str4 Ljava/lang/String;
77 5 5 e1 Ljava/lang/Exception;
এটি মূলত আমরা যা দেখছি। উদাহরণ কোডে প্রথম অনুরোধটি লাইন 17 line লাইননিবারটবেলে লাইন 17 দেখায় যে সেই লাইনের শুরুটি বাইটকোড লাইন সূচক 18 index এটি System.outলোড। তারপরে আমাদের কাছে aload_2পদ্ধতি কলের ঠিক আগে উপস্থিত রয়েছে তাই আমরা লোকাল ভারিটেবল টেবিলের স্লট 2 তে পরিবর্তনশীলটি সন্ধান করি যা strএই ক্ষেত্রে রয়েছে।
মজাদার জন্য, এখানে একটি যা একই লাইনে একাধিক ফাংশন কল পরিচালনা করে। এর ফলে ফাংশনটি আদর্শবান হতে না পারে তবে এ জাতীয় বিন্দু। এটি অনলাইন চেষ্টা করুন!