| /* |
| * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0, which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * This Source Code may also be made available under the following Secondary |
| * Licenses when the conditions for such availability set forth in the |
| * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, |
| * version 2 with the GNU Classpath Exception, which is available at |
| * https://www.gnu.org/software/classpath/license.html. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 |
| */ |
| |
| /** |
| * WBN -- generic mechanism for simulating toString() and equals() |
| * for any class |
| */ |
| package com.sun.enterprise.util; |
| // |
| |
| import java.lang.reflect.*; |
| import java.util.Vector; |
| import java.util.logging.*; |
| |
| public class ObjectAnalyzer { |
| /** |
| * @param className |
| * @return */ |
| public static String getMethods(String className) { |
| try { |
| Class clazz = Class.forName(className); |
| return getMethods(clazz, false); |
| } |
| catch (Exception e) { |
| return "Error loading class: " + e.getMessage();//NOI18N |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| /** |
| * @param obj |
| * @return */ |
| public static String getMethods(Object obj) { |
| return getMethods(obj, false); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| /** |
| * @param obj |
| * @param settersOnly |
| * @return */ |
| public static String getMethods(Object obj, boolean settersOnly) { |
| try { |
| Class clazz = safeGetClass(obj); |
| return getMethods(clazz, settersOnly); |
| } |
| catch (Exception e) { |
| return e.getMessage(); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| /** |
| * @param clazz |
| * @param settersOnly |
| * @return */ |
| public static String getMethods(Class clazz, boolean settersOnly) { |
| StringBuilder sb = new StringBuilder(); |
| |
| Method[] methods = clazz.getMethods(); |
| |
| for (int i = 0; i < methods.length; i++) { |
| Method m = methods[i]; |
| boolean isSetter = m.getName().startsWith("set");//NOI18N |
| |
| if (settersOnly && isSetter == false) |
| continue; |
| |
| sb.append(m.toString()).append('\n'); |
| } |
| return sb.toString(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| /** |
| * @param obj |
| * @return */ |
| public static String getSetters(Object obj) { |
| return getMethods(obj, true); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| /** |
| * @param clazz |
| * @return */ |
| public static String getSetters(Class clazz) { |
| return getMethods(clazz, true); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| /** |
| * @param obj |
| * @return */ |
| public static String toString(Object obj) { |
| return toString(obj, false); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| /** |
| * @param obj |
| * @return */ |
| public static String toStringWithSuper(Object obj) { |
| return toString(obj, true); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| /** |
| * @param a |
| * @param b |
| * @return */ |
| public static boolean equals(Object a, Object b) { |
| Class cl = a.getClass(); |
| |
| if (!cl.equals(b.getClass())) |
| return false; |
| |
| Field[] fields = cl.getDeclaredFields(); |
| setAccessible(fields); |
| |
| for (int i = 0; i < fields.length; i++) { |
| Field f = fields[i]; |
| try { |
| if (!f.get(a).equals(f.get(b))) |
| return false; |
| } |
| catch (IllegalAccessException e) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| public static void useShortClassNames() { |
| useShortClassNames_ = true; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| public static void useLongClassNames() { |
| useShortClassNames_ = false; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| private static String toString(Object obj, boolean doSuperClasses) { |
| try { |
| return getFieldInfo(obj, doSuperClasses).toString(); |
| } |
| catch (ObjectAnalyzerException e) { |
| return e.getMessage(); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| private static Class safeGetClass(Object obj) throws ObjectAnalyzerException { |
| if (obj == null) |
| throw new ObjectAnalyzerException(fatal + "null Object parameter");//NOI18N |
| |
| Class cl = obj.getClass(); |
| |
| if (cl == null) |
| throw new ObjectAnalyzerException(fatal + "getClass() on parameter Object returned null");//NOI18N |
| |
| return cl; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| private static Class safeGetSuperclass(Class cl) throws ObjectAnalyzerException { |
| Class sc = cl.getSuperclass(); |
| |
| if (sc == null) |
| throw new ObjectAnalyzerException("getSuperclass() on parameter Object returned null");//NOI18N |
| |
| return sc; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| private static FieldInfoVector getFieldInfo(Object obj, boolean doSuperClasses) throws ObjectAnalyzerException { |
| FieldInfoVector fiv = new FieldInfoVector(); |
| Class cl = safeGetClass(obj); |
| |
| if (doSuperClasses == false) { |
| getFieldInfo(cl, obj, fiv); |
| return fiv; |
| } |
| |
| for (Class theClass = cl; !theClass.equals(Object.class); theClass = safeGetSuperclass(theClass)) |
| getFieldInfo(theClass, obj, fiv); |
| |
| return fiv; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| private static void getFieldInfo(Class cl, Object obj, FieldInfoVector fiv) throws ObjectAnalyzerException { |
| Field[] fields = null; |
| |
| try { |
| fields = cl.getDeclaredFields(); |
| } |
| catch (SecurityException e) { |
| throw new ObjectAnalyzerException("got a SecurityException when calling getDeclaredFields() on " + cl.getName());//NOI18N |
| } |
| |
| // FindBugs says this is a redundant null check. We are now depending |
| // on (assuming) that getDeclaredFields() will never return null; |
| //if (fields == null) |
| //throw new ObjectAnalyzerException("calling getDeclaredFields() on " + cl.getName() + " returned null");//NOI18N |
| |
| setAccessible(fields); |
| |
| for (int i = 0; i < fields.length; i++) { |
| Field f = fields[i]; |
| String sval; |
| String modifiers = Modifier.toString(f.getModifiers()); |
| String className = cl.getName(); |
| |
| if (useShortClassNames_) |
| className = StringUtils.toShortClassName(className); |
| |
| if (modifiers.length() <= 0) |
| modifiers = "(package)";//NOI18N |
| |
| try { |
| Object val = f.get(obj); |
| |
| if (val == null) |
| sval = "<null>";//NOI18N |
| else |
| sval = val.toString(); |
| } |
| catch (IllegalAccessException e) { |
| sval = "<IllegalAccessException>";//NOI18N |
| } |
| |
| fiv.addElement(new FieldInfo(className, f, sval, modifiers)); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| private static void setAccessible(Field[] fields) { |
| if (setAccessibleMethod == null) |
| return; // Must be pre JDK 1.2.x |
| |
| try { |
| Boolean b = Boolean.valueOf(true); |
| setAccessibleMethod.invoke(null, new Object[]{fields, b}); |
| } |
| catch (Exception e) { |
| Logger.getAnonymousLogger().warning("Got an exception invoking setAccessible: " + e);//NOI18N |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| private static void setupSetAccessibleMethod() { |
| // whoa! what's this reflection stuff doing here? |
| // AccessibleObject is a JDK 1.2 class that lets you peek at |
| // private variable values. Since we need to support JDK 1.1 |
| // for the VCafe plug-in -- it is now called via 100% reflection |
| // techniques... |
| |
| setAccessibleMethod = null; |
| |
| Class AO; |
| |
| try { |
| AO = Class.forName("java.lang.reflect.AccessibleObject");//NOI18N |
| } |
| catch (ClassNotFoundException e) { |
| Logger.getAnonymousLogger().info("Can't find java.lang.reflect.AccessibleObject -- thus I can't show any private or protected variable values. This must be pre JDK 1.2.x");//NOI18N |
| return; |
| } |
| |
| Method[] methods = AO.getDeclaredMethods(); |
| |
| for (int i = 0; i < methods.length; i++) { |
| Method m = methods[i]; |
| |
| if (m.getName().equals("setAccessible") && m.getParameterTypes().length == 2)//NOI18N |
| { |
| if(Logger.getAnonymousLogger().isLoggable(Level.FINER)) |
| Logger.getAnonymousLogger().finer("Found setAccessible: " + m);//NOI18N |
| setAccessibleMethod = m; |
| break; |
| } |
| } |
| } |
| //////////////////////////////////////////////////////////////////////////// |
| private static final String fatal = "Fatal Error in ObjectAnalyzer.toString(): ";//NOI18N |
| private static boolean useShortClassNames_ = true; |
| private static Method setAccessibleMethod; |
| |
| static { |
| setupSetAccessibleMethod(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| /** |
| * @param args */ |
| public static void main(String[] args) { |
| String s = "Hello!";//NOI18N |
| |
| System.out.println("Regular: \n" + toString(s) + "\n\n");//NOI18N |
| System.out.println("Super: \n" + toStringWithSuper(s) + "\n\n");//NOI18N |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| //////////////////////////////////////////////////////////////////////////// |
| class ObjectAnalyzerException extends Exception { |
| ObjectAnalyzerException(String s) { |
| super(s); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| //////////////////////////////////////////////////////////////////////////// |
| class FieldInfo { |
| Field field; |
| String value; |
| //Class clazz; |
| String className; |
| String modifiers; |
| |
| FieldInfo(String c, Field f, String v, String m) { |
| className = c; |
| field = f; |
| value = v; |
| modifiers = m; |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| //////////////////////////////////////////////////////////////////////////// |
| class FieldInfoVector // { extends Vector |
| { |
| Vector v = null; |
| |
| FieldInfoVector() { |
| v = new Vector(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| /** |
| * @param o */ |
| public void addElement(Object o) { |
| v.addElement(o); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| /** |
| * @return */ |
| public String toString() { |
| int veclen = v.size(); |
| StringBuffer s = new StringBuffer(); |
| |
| setLongestNames(); |
| |
| //s.append("classNameLength: " + classNameLength + "fieldNameLength: " + fieldNameLength + "modifiersLength: " + modifiersLength + "\n\n");//NOI18N |
| |
| s.append(StringUtils.padRight("Class", classNameLength));//NOI18N |
| s.append(StringUtils.padRight("Modifiers", modifiersLength));//NOI18N |
| s.append(StringUtils.padRight("Field", fieldNameLength));//NOI18N |
| s.append("Value");//NOI18N |
| s.append("\n\n");//NOI18N |
| |
| for (int i = 0; i < veclen; i++) { |
| FieldInfo fi = fetch(i); |
| |
| s.append(StringUtils.padRight(fi.className, classNameLength)); |
| s.append(StringUtils.padRight(fi.modifiers, modifiersLength)); |
| s.append(StringUtils.padRight(fi.field.getName(), fieldNameLength)); |
| s.append(fi.value); |
| s.append('\n'); |
| } |
| |
| return s.toString(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| private FieldInfo fetch(int i) { |
| return (FieldInfo) v.elementAt(i); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| private void setLongestNames() { |
| int veclen = v.size(); |
| |
| classNameLength = 5; |
| fieldNameLength = 5; |
| modifiersLength = 5; |
| |
| for (int i = 0; i < veclen; i++) { |
| FieldInfo fi = fetch(i); |
| |
| int clen = fi.className.length(); |
| int flen = fi.field.getName().length(); |
| int mlen = fi.modifiers.length(); |
| if (clen > classNameLength) |
| classNameLength = clen; |
| if (flen > fieldNameLength) |
| fieldNameLength = flen; |
| if (mlen > modifiersLength) |
| modifiersLength = mlen; |
| } |
| |
| classNameLength += 2; |
| fieldNameLength += 2; |
| modifiersLength += 2; |
| } |
| //////////////////////////////////////////////////////////////////////////// |
| private int classNameLength = 0; |
| private int fieldNameLength = 0; |
| private int modifiersLength = 0; |
| } |