jar2xml

16:37:00.217 INFO  jd.cli.Main - Decompiling jar2xml.jar
package jar2xml;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.objectweb.asm.tree.ClassNode;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public abstract class AndroidDocScraper
  implements IDocScraper
{
  final String pattern_head;
  final String reset_pattern_head;
  final String parameter_pair_splitter;
  final boolean continuous_param_lines;
  File root;
  static Map<String, List<String>> deprecatedFields;
  static Map<String, List<String>> deprecatedMethods;
  
  protected AndroidDocScraper(File dir, String patternHead, String resetPatternHead, String parameterPairSplitter, boolean continuousParamLines)
    throws IOException
  {
    if (dir == null) {
      throw new IllegalArgumentException();
    }
    pattern_head = patternHead;
    reset_pattern_head = resetPatternHead;
    parameter_pair_splitter = (parameterPairSplitter != null ? parameterPairSplitter : "\\s+");
    continuous_param_lines = continuousParamLines;
    if (!dir.exists()) {
      throw new FileNotFoundException(dir.getAbsolutePath());
    }
    if (!dir.isDirectory()) {
      throw new IllegalArgumentException(dir.getAbsolutePath() + " is not a directory.");
    }
    root = dir;
    if ((!new File(dir.getAbsolutePath() + "/package-list").isFile()) && (!new File(dir.getAbsolutePath() + "/packages.html").isFile())) {
      throw new IllegalArgumentException(dir.getAbsolutePath() + " does not appear to be an android doc reference directory.");
    }
  }
  
  public String[] getParameterNames(ClassNode asm, String name, Type[] ptypes, boolean isVarArgs)
  {
    String path = name.replace('$', '.') + ".html";
    File file = new File(root.getPath() + "/" + path);
    if (!file.isFile()) {
      return null;
    }
    StringBuffer buffer = new StringBuffer();
    buffer.append(pattern_head);
    buffer.append(path);
    buffer.append("#");
    buffer.append(name);
    buffer.append("\\(\\Q");
    for (int i = 0; i < ptypes.length; i++)
    {
      if (i != 0) {
        buffer.append(", ");
      }
      String type = JavaClass.getGenericTypeName(ptypes[i]);
      if ((isVarArgs) && (i == ptypes.length - 1)) {
        type = type.replace("[]", "...");
      }
      buffer.append(type);
    }
    buffer.append("\\E\\)\".*\\((.*)\\)");
    Pattern pattern = Pattern.compile(buffer.toString());
    try
    {
      FileInputStream stream = new FileInputStream(file);
      try
      {
        InputStreamReader rdr = new InputStreamReader(stream, "UTF-8");
        BufferedReader br = new BufferedReader(rdr);
        String text = "";
        String prev = null;
        while ((text = br.readLine()) != null)
        {
          if (prev != null) {
            prev = text = prev + text;
          }
          Matcher matcher = pattern.matcher(text);
          if (matcher.find())
          {
            String plist = matcher.group(1);
            String[] parms = plist.split(", ");
            if (parms.length != ptypes.length) {
              System.err.println("failed matching " + buffer.toString());
            }
            String[] result = new String[ptypes.length];
            for (int i = 0; i < ptypes.length; i++)
            {
              String[] toks = parms[i].split(parameter_pair_splitter);
              result[i] = toks[(toks.length - 1)];
            }
            stream.close();
            return result;
          }
          if ((reset_pattern_head == null) || (text.endsWith(">")) || ((!continuous_param_lines) && (!text.startsWith(reset_pattern_head)))) {
            prev = null;
          } else {
            prev = text;
          }
        }
      }
      finally
      {
        stream.close();
      }
    }
    catch (Exception e)
    {
      return new String[0];
    }
    return new String[0];
  }
  
  public static void loadXml(String filename)
  {
    try
    {
      Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(filename);
      deprecatedFields = new HashMap();
      deprecatedMethods = new HashMap();
      NodeList files = doc.getDocumentElement().getElementsByTagName("file");
      for (int i = 0; i < files.getLength(); i++)
      {
        Element file = (Element)files.item(i);
        ArrayList<String> f = new ArrayList();
        deprecatedFields.put(file.getAttribute("name"), f);
        NodeList fields = file.getElementsByTagName("field");
        for (int j = 0; j < fields.getLength(); j++) {
          f.add(fields.item(j).getTextContent());
        }
        ArrayList<String> m = new ArrayList();
        deprecatedMethods.put(file.getAttribute("name"), m);
        NodeList methods = file.getElementsByTagName("method");
        for (int j = 0; j < methods.getLength(); j++) {
          m.add(methods.item(j).getTextContent());
        }
      }
    }
    catch (Exception ex)
    {
      System.err.println("Annotations parser error: " + ex);
    }
  }
  
  public static List<String> getDeprecatedFields(ClassNode asm)
  {
    if (deprecatedFields == null) {
      return null;
    }
    return (List)deprecatedFields.get(name.replace('$', '.'));
  }
  
  public static List<String> getDeprecatedMethods(ClassNode asm)
  {
    if (deprecatedMethods == null) {
      return null;
    }
    return (List)deprecatedMethods.get(name.replace('$', '.'));
  }
}

/* Location:
 * Qualified Name:     jar2xml.AndroidDocScraper
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package jar2xml;

import java.io.File;
import java.io.IOException;

class DroidDocScraper
  extends AndroidDocScraper
{
  static final String pattern_head_droiddoc = "<span class=\"sympad\"><a href=\".*";
  
  public DroidDocScraper(File dir)
    throws IOException
  {
    super(dir, "<span class=\"sympad\"><a href=\".*", null, null, false);
  }
}

/* Location:
 * Qualified Name:     jar2xml.DroidDocScraper
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package jar2xml;

import java.lang.reflect.Type;
import org.objectweb.asm.tree.ClassNode;

public abstract interface IDocScraper
{
  public abstract String[] getParameterNames(ClassNode paramClassNode, String paramString, Type[] paramArrayOfType, boolean paramBoolean);
}

/* Location:
 * Qualified Name:     jar2xml.IDocScraper
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package jar2xml;

import java.io.File;
import java.io.IOException;

class Java7DocScraper
  extends AndroidDocScraper
{
  static final String pattern_head_javadoc = "<td class=\"col.+\"><code><strong><a href=\"[./]*";
  static final String reset_pattern_head_javadoc = "<td><code>";
  static final String parameter_pair_splitter_javadoc = "&nbsp;";
  
  public Java7DocScraper(File dir)
    throws IOException
  {
    super(dir, "<td class=\"col.+\"><code><strong><a href=\"[./]*", "<td><code>", "&nbsp;", true);
  }
}

/* Location:
 * Qualified Name:     jar2xml.Java7DocScraper
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package jar2xml;

import java.io.File;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.ClassNode;

public class JavaArchive
{
  private List<JarFile> files = new ArrayList();
  private ClassLoader loader;
  
  public JavaArchive(List<String> filenames, List<String> additionalJars)
    throws Exception
  {
    List<URL> urls = new ArrayList();
    for (String filename : filenames)
    {
      files.add(new JarFile(filename));
      urls.add(new File(filename).getAbsoluteFile().toURL());
    }
    for (String additionalJar : additionalJars) {
      urls.add(new File(additionalJar).getAbsoluteFile().toURL());
    }
    URL[] urlsArray = new URL[urls.size()];
    urls.toArray(urlsArray);
    loader = new URLClassLoader(urlsArray, JavaArchive.class.getClassLoader());
  }
  
  public List<JavaPackage> getPackages()
  {
    HashMap<String, JavaPackage> packages = new HashMap();
    for (JarFile file : files) {
      getPackages(packages, file);
    }
    ArrayList<JavaPackage> result = new ArrayList(packages.values());
    Collections.sort(result);
    return result;
  }
  
  void getPackages(HashMap<String, JavaPackage> packages, JarFile file)
  {
    Enumeration<JarEntry> entries = file.entries();
    while (entries.hasMoreElements())
    {
      JarEntry entry = (JarEntry)entries.nextElement();
      String name = entry.getName();
      if (name.endsWith(".class"))
      {
        name = name.substring(0, name.length() - 6);
        try
        {
          InputStream stream = file.getInputStream(entry);
          ClassReader reader = new ClassReader(stream);
          ClassNode node = new ClassNode();
          reader.accept(node, 0);
          JavaClass.asmClasses.put(name, node);
          
          Class c = loader.loadClass(name.replace('/', '.'));
          
          String pkgname = name.substring(0, name.lastIndexOf('/')).replace('/', '.');
          
          JavaPackage pkg = (JavaPackage)packages.get(pkgname);
          if (pkg == null)
          {
            pkg = new JavaPackage(pkgname);
            packages.put(pkgname, pkg);
          }
          pkg.addClass(new JavaClass(c, node));
        }
        catch (Throwable t)
        {
          t.printStackTrace();
          System.err.println("warning J2X9001: Couldn't load class " + name + " : " + t);
        }
      }
    }
  }
}

/* Location:
 * Qualified Name:     jar2xml.JavaArchive
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package jar2xml;

import java.util.Comparator;

final class JavaClass$1
  implements Comparator
{
  public int compare(Object o1, Object o2)
  {
    return ((Class)o1).getSimpleName().compareTo(((Class)o2).getSimpleName());
  }
  
  public boolean equals(Object obj)
  {
    return super.equals(obj);
  }
}

/* Location:
 * Qualified Name:     jar2xml.JavaClass.1
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package jar2xml;

import java.lang.reflect.Type;
import java.util.Comparator;

final class JavaClass$2
  implements Comparator
{
  public int compare(Object o1, Object o2)
  {
    if (((o1 instanceof Class)) && ((o2 instanceof Class))) {
      return ((Class)o1).getName().compareTo(((Class)o2).getName());
    }
    return JavaClass.getGenericTypeName((Type)o1).compareTo(JavaClass.getGenericTypeName((Type)o2));
  }
  
  public boolean equals(Object obj)
  {
    return super.equals(obj);
  }
}

/* Location:
 * Qualified Name:     jar2xml.JavaClass.2
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package jar2xml;

import java.util.Comparator;

class JavaClass$3
  implements Comparator<Class>
{
  JavaClass$3(JavaClass paramJavaClass) {}
  
  public int compare(Class c1, Class c2)
  {
    return c1.getName().compareTo(c2.getName());
  }
}

/* Location:
 * Qualified Name:     jar2xml.JavaClass.3
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package jar2xml;

import java.lang.reflect.Field;
import java.util.Comparator;

class JavaClass$4
  implements Comparator<Field>
{
  JavaClass$4(JavaClass paramJavaClass) {}
  
  public int compare(Field f1, Field f2)
  {
    return f1.getName().compareTo(f2.getName());
  }
  
  public boolean equals(Object obj)
  {
    return obj == this;
  }
}

/* Location:
 * Qualified Name:     jar2xml.JavaClass.4
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package jar2xml;

import java.io.PrintStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Pattern;
import javax.net.ServerSocketFactory;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class JavaClass
  implements Comparable<JavaClass>
{
  public static Map<String, ClassNode> asmClasses = new HashMap();
  private Class jclass;
  private ClassNode asm;
  private Map<String, FieldNode> asmFields;
  private List<String> deprecatedFields;
  private List<String> deprecatedMethods;
  private boolean is_obfuscated;
  
  public JavaClass(Class jclass, ClassNode asm)
  {
    this.jclass = jclass;
    this.asm = asm;
    deprecatedFields = AndroidDocScraper.getDeprecatedFields(asm);
    deprecatedMethods = AndroidDocScraper.getDeprecatedMethods(asm);
    asmFields = new HashMap();
    for (FieldNode fn : fields) {
      asmFields.put(name, fn);
    }
  }
  
  public int compareTo(JavaClass jc)
  {
    return getName().compareTo(jc.getName());
  }
  
  public String getName()
  {
    return asm.name.replace('/', '.');
  }
  
  public boolean isObfuscated()
  {
    return is_obfuscated;
  }
  
  public void setObfuscated(boolean value)
  {
    is_obfuscated = value;
  }
  
  String[] getParameterNames(String name, Type[] types, boolean isVarArgs)
  {
    for (IDocScraper s : scrapers)
    {
      String[] names = s.getParameterNames(asm, name, types, isVarArgs);
      if ((names != null) && (names.length > 0)) {
        return names;
      }
    }
    return null;
  }
  
  void appendParameters(String name, Type[] types, int typeOffset, boolean isVarArgs, Document doc, Element parent)
  {
    if ((types == null) || (types.length == 0)) {
      return;
    }
    String[] names = getParameterNames(name, types, isVarArgs);
    
    int cnt = 0;
    for (int i = typeOffset; i < types.length; i++)
    {
      Element e = doc.createElement("parameter");
      e.setAttribute("name", names == null ? "p" + i : names[i]);
      String type = getGenericTypeName(types[i]);
      if ((isVarArgs) && (i == types.length - 1)) {
        type = type.replace("[]", "...");
      }
      e.setAttribute("type", type);
      e.appendChild(doc.createTextNode("\n"));
      parent.appendChild(e);
    }
  }
  
  String getSimpleName(ClassNode asm)
  {
    return name.substring(name.lastIndexOf('/') + 1).replace('$', '.');
  }
  
  void appendCtor(Constructor ctor, Document doc, Element parent)
  {
    try
    {
      doAppendCtor(ctor, doc, parent);
    }
    catch (NoClassDefFoundError ex)
    {
      System.err.println("warning J2XA001: missing class error was raised while reflecting " + ctor.getName() + " [" + ctor + "] : " + ex.getMessage());
    }
  }
  
  void doAppendCtor(Constructor ctor, Document doc, Element parent)
  {
    int mods = ctor.getModifiers();
    if ((!Modifier.isPublic(mods)) && (!Modifier.isProtected(mods))) {
      return;
    }
    Element e = doc.createElement("constructor");
    e.setAttribute("name", getSimpleName(asm));
    e.setAttribute("type", getClassName(jclass, true));
    e.setAttribute("final", Modifier.isFinal(mods) ? "true" : "false");
    e.setAttribute("static", Modifier.isStatic(mods) ? "true" : "false");
    e.setAttribute("visibility", Modifier.isPublic(mods) ? "public" : "protected");
    setDeprecatedAttr(e, ctor.getDeclaredAnnotations(), e.getAttribute("name"));
    
    appendParameters(parent.getAttribute("name"), getGenericParameterTypes(ctor), getConstructorParameterOffset(ctor), ctor.isVarArgs(), doc, e);
    e.appendChild(doc.createTextNode("\n"));
    parent.appendChild(e);
  }
  
  Type[] getGenericParameterTypes(Method m)
  {
    try
    {
      return m.getGenericParameterTypes();
    }
    catch (Throwable ex)
    {
      ex.printStackTrace();
      System.err.println("warning J2XA00A: Java reflection engine failed to get generic parameter types for method '" + m + "'. For details, check verbose build output.");
    }
    return m.getParameterTypes();
  }
  
  Type[] getGenericParameterTypes(Constructor m)
  {
    try
    {
      return m.getGenericParameterTypes();
    }
    catch (Throwable ex)
    {
      ex.printStackTrace();
      System.err.println("warning J2XA00B: Java reflection engine failed to get generic parameter types for constructor '" + m + "'. For details, check verbose build output.");
    }
    return m.getParameterTypes();
  }
  
  Type getGenericType(Field f)
  {
    try
    {
      return f.getGenericType();
    }
    catch (Throwable ex)
    {
      ex.printStackTrace();
      System.err.println("warning J2XA00C: Java reflection engine failed to get generic type for field '" + f + "'. For details, check verbose build output.");
    }
    return f.getType();
  }
  
  Type getGenericReturnType(Method m)
  {
    try
    {
      return m.getGenericReturnType();
    }
    catch (Throwable ex)
    {
      ex.printStackTrace();
      System.err.println("warning J2XA00D: Java reflection engine failed to get generic return type for method '" + m + "'. For details, check verbose build output.");
    }
    return m.getReturnType();
  }
  
  Type getGenericSuperclass(Class c)
  {
    try
    {
      return c.getGenericSuperclass();
    }
    catch (Throwable ex)
    {
      ex.printStackTrace();
      System.err.println("warning J2XA00E: Java reflection engine failed to get generic super class for class '" + c + "'. For details, check verbose build output.");
    }
    return c.getSuperclass();
  }
  
  Type[] getGenericInterfaces(Class c)
  {
    try
    {
      return c.getGenericInterfaces();
    }
    catch (Throwable ex)
    {
      ex.printStackTrace();
      System.err.println("warning J2XA00F: Java reflection engine failed to get generic interface types for class '" + c + "'. For details, check verbose build output.");
    }
    return c.getInterfaces();
  }
  
  static Type[] getActualTypeArguments(ParameterizedType ptype)
  {
    Type[] types = ptype.getActualTypeArguments();
    for (Type t : types) {
      if (t == null) {
        return new Type[0];
      }
    }
    return types;
  }
  
  int getConstructorParameterOffset(Constructor ctor)
  {
    if (Modifier.isStatic(jclass.getModifiers())) {
      return 0;
    }
    Type[] params = getGenericParameterTypes(ctor);
    if ((params.length > 0) && (params[0].equals(jclass.getDeclaringClass()))) {
      return 1;
    }
    return 0;
  }
  
  void appendField(Field field, FieldNode asmField, Document doc, Element parent)
  {
    try
    {
      doAppendField(field, asmField, doc, parent);
    }
    catch (NoClassDefFoundError ex)
    {
      System.err.println("warning J2XA002: missing class error was raised while reflecting " + field.getName() + " [" + field + "] : " + ex.getMessage());
    }
  }
  
  void doAppendField(Field field, FieldNode asmField, Document doc, Element parent)
  {
    int mods = field.getModifiers();
    if ((!Modifier.isPublic(mods)) && (!Modifier.isProtected(mods))) {
      return;
    }
    Element e = doc.createElement("field");
    e.setAttribute("name", field.getName());
    e.setAttribute("type", getClassName(field.getType(), true));
    e.setAttribute("type-generic-aware", getGenericTypeName(getGenericType(field)));
    e.setAttribute("final", Modifier.isFinal(mods) ? "true" : "false");
    e.setAttribute("static", Modifier.isStatic(mods) ? "true" : "false");
    if (Modifier.isAbstract(mods)) {
      e.setAttribute("abstract", "true");
    }
    e.setAttribute("transient", Modifier.isTransient(mods) ? "true" : "false");
    e.setAttribute("visibility", Modifier.isPublic(mods) ? "public" : "protected");
    e.setAttribute("volatile", Modifier.isVolatile(mods) ? "true" : "false");
    setDeprecatedAttr(e, field.getDeclaredAnnotations(), e.getAttribute("name"));
    if (asmField == null)
    {
      System.err.println("warning J2XA003: asm failed to retrieve FieldNode for " + field);
    }
    else if (value != null)
    {
      String type = e.getAttribute("type");
      boolean isPublic = Modifier.isPublic(mods);
      Locale invariant = Locale.US;
      try
      {
        if (type == "int")
        {
          e.setAttribute("value", String.format("%d", new Object[] { value }));
        }
        else if (type == "byte")
        {
          e.setAttribute("value", String.format("%d", new Object[] { value }));
        }
        else if (type == "char")
        {
          e.setAttribute("value", String.format("%d", new Object[] { value }));
        }
        else if (type == "short")
        {
          e.setAttribute("value", String.format("%d", new Object[] { value }));
        }
        else if (type == "long")
        {
          e.setAttribute("value", String.format("%dL", new Object[] { value }));
        }
        else if (type == "float")
        {
          double fvalue = ((Float)value).floatValue();
          String svalue;
          String svalue;
          if (fvalue == 1.1754943508222875E-38D) {
            svalue = "1.17549435E-38";
          } else {
            svalue = String.format(invariant, "%f", new Object[] { value });
          }
          e.setAttribute("value", svalue);
        }
        else if (type == "double")
        {
          double dvalue = ((Double)value).doubleValue();
          String svalue;
          String svalue;
          if (dvalue == Double.MAX_VALUE)
          {
            svalue = "1.7976931348623157E308";
          }
          else
          {
            String svalue;
            if (dvalue == Double.MIN_VALUE)
            {
              svalue = "4.9E-324";
            }
            else
            {
              String svalue;
              if (dvalue == 2.2250738585072014E-308D)
              {
                svalue = "2.2250738585072014E-308";
              }
              else
              {
                String svalue;
                if (Double.isNaN(dvalue))
                {
                  svalue = "(0.0 / 0.0)";
                }
                else
                {
                  String svalue;
                  if (dvalue == Double.POSITIVE_INFINITY)
                  {
                    svalue = "(1.0 / 0.0)";
                  }
                  else
                  {
                    String svalue;
                    if (dvalue == Double.NEGATIVE_INFINITY) {
                      svalue = "(-1.0 / 0.0)";
                    } else {
                      svalue = String.format(invariant, "%.15f", new Object[] { Double.valueOf(dvalue) });
                    }
                  }
                }
              }
            }
          }
          e.setAttribute("value", svalue);
        }
        else if (type == "boolean")
        {
          e.setAttribute("value", 0 == ((Integer)value).intValue() ? "false" : "true");
        }
        else if (type == "java.lang.String")
        {
          String value = (String)value;
          if (value != null) {
            e.setAttribute("value", "\"" + escapeLiteral(value.replace("\\", "\\\\").replace("\"", "\\\"")) + "\"");
          }
        }
        else if ((Modifier.isStatic(mods)) && (e.getAttribute("type").endsWith("[]")))
        {
          e.setAttribute("value", "null");
        }
      }
      catch (Throwable exc)
      {
        System.err.println("warning J2XA004: error accessing constant field " + field.getName() + " value for class " + getName() + " : " + exc.getMessage());
      }
    }
    else if ((!Modifier.isStatic(mods)) && (e.getAttribute("type").endsWith("[]")))
    {
      e.setAttribute("value", "null");
    }
    e.appendChild(doc.createTextNode("\n"));
    parent.appendChild(e);
  }
  
  String escapeLiteral(String s)
  {
    for (int i = 0; i < s.length(); i++) {
      if ((s.charAt(i) < ' ') || ('�' <= s.charAt(i))) {
        return doEscapeLiteral(new StringBuilder(s), i);
      }
    }
    return s;
  }
  
  String doEscapeLiteral(StringBuilder s, int i)
  {
    s.replace(i, i + 1, String.format("\\u%1$04X", new Object[] { Integer.valueOf(s.charAt(i)) }));
    i += 4;
    for (; i < s.length(); i++) {
      if ((s.charAt(i) < ' ') || ('�' <= s.charAt(i))) {
        return doEscapeLiteral(s, i);
      }
    }
    return s.toString();
  }
  
  void appendMethod(Method method, Document doc, Element parent)
  {
    try
    {
      doAppendMethod(method, doc, parent);
    }
    catch (NoClassDefFoundError ex)
    {
      System.err.println("warning J2XA005: missing class error was raised while reflecting " + method.getName() + " [" + method + "] : " + ex.getMessage());
    }
  }
  
  void doAppendMethod(Method method, Document doc, Element parent)
  {
    int mods = method.getModifiers();
    if ((!Modifier.isPublic(mods)) && (!Modifier.isProtected(mods))) {
      return;
    }
    Element e = doc.createElement("method");
    e.setAttribute("name", method.getName());
    Element typeParameters = getTypeParametersNode(doc, method.getTypeParameters());
    if (typeParameters != null) {
      e.appendChild(typeParameters);
    }
    e.setAttribute("return", getGenericTypeName(getGenericReturnType(method)));
    e.setAttribute("final", Modifier.isFinal(mods) ? "true" : "false");
    e.setAttribute("static", Modifier.isStatic(mods) ? "true" : "false");
    e.setAttribute("abstract", Modifier.isAbstract(mods) ? "true" : "false");
    e.setAttribute("native", Modifier.isNative(mods) ? "true" : "false");
    if ((jclass.equals(ServerSocketFactory.class)) && (method.getName().equals("getDefault"))) {
      e.setAttribute("synchronized", "true");
    } else {
      e.setAttribute("synchronized", Modifier.isSynchronized(mods) ? "true" : "false");
    }
    e.setAttribute("visibility", Modifier.isPublic(mods) ? "public" : "protected");
    
    String easyName = method.getName() + "(";
    Class[] ptypes = method.getParameterTypes();
    for (int idx = 0; idx < ptypes.length; idx++) {
      easyName = easyName + (idx > 0 ? "," : "") + ptypes[idx].getSimpleName();
    }
    easyName = easyName + ")";
    setDeprecatedAttr(e, method.getDeclaredAnnotations(), easyName);
    
    appendParameters(method.getName(), getGenericParameterTypes(method), 0, method.isVarArgs(), doc, e);
    
    Class[] excTypes = method.getExceptionTypes();
    sortClasses(excTypes);
    for (Class exc : excTypes)
    {
      Element exe = doc.createElement("exception");
      exe.setAttribute("name", getClassName(exc, false));
      exe.setAttribute("type", getClassName(exc, true));
      exe.appendChild(doc.createTextNode("\n"));
      e.appendChild(exe);
    }
    e.appendChild(doc.createTextNode("\n"));
    parent.appendChild(e);
  }
  
  static void sortClasses(Class[] classes)
  {
    Arrays.sort(classes, new Comparator()
    {
      public int compare(Object o1, Object o2)
      {
        return ((Class)o1).getSimpleName().compareTo(((Class)o2).getSimpleName());
      }
      
      public boolean equals(Object obj)
      {
        return super.equals(obj);
      }
    });
  }
  
  static void sortTypes(Type[] types)
  {
    Arrays.sort(types, new Comparator()
    {
      public int compare(Object o1, Object o2)
      {
        if (((o1 instanceof Class)) && ((o2 instanceof Class))) {
          return ((Class)o1).getName().compareTo(((Class)o2).getName());
        }
        return JavaClass.getGenericTypeName((Type)o1).compareTo(JavaClass.getGenericTypeName((Type)o2));
      }
      
      public boolean equals(Object obj)
      {
        return super.equals(obj);
      }
    });
  }
  
  static String getTypeParameters(TypeVariable<?>[] typeParameters)
  {
    if (typeParameters.length == 0) {
      return "";
    }
    StringBuffer type_params = new StringBuffer();
    type_params.append("<");
    for (TypeVariable tp : typeParameters)
    {
      if (type_params.length() > 1) {
        type_params.append(", ");
      }
      type_params.append(tp.getName());
      Type[] bounds = tp.getBounds();
      if ((bounds.length != 1) || (bounds[0] != Object.class))
      {
        type_params.append(" extends ").append(getGenericTypeName(bounds[0]));
        for (int i = 1; i < bounds.length; i++) {
          type_params.append(" & ").append(getGenericTypeName(bounds[i]));
        }
      }
    }
    type_params.append(">");
    return type_params.toString();
  }
  
  static Element getTypeParametersNode(Document doc, TypeVariable<Method>[] tps)
  {
    if (tps.length == 0) {
      return null;
    }
    try
    {
      return doGetTypeParametersNode(doc, tps);
    }
    catch (TypeNotPresentException ex)
    {
      System.err.println("warning J2XA010: referenced type was not present: " + ex.getMessage());
      return null;
    }
    catch (NoClassDefFoundError ex)
    {
      System.err.println("warning J2XA011: missing class error was raised: " + ex.getMessage());
    }
    return null;
  }
  
  static Element doGetTypeParametersNode(Document doc, TypeVariable<Method>[] tps)
  {
    if (tps.length == 0) {
      return null;
    }
    Element tps_elem = doc.createElement("typeParameters");
    for (TypeVariable<?> tp : tps)
    {
      Element tp_elem = doc.createElement("typeParameter");
      tp_elem.setAttribute("name", tp.getName());
      if ((tp.getBounds().length != 1) || (!tp.getBounds()[0].equals(Object.class)))
      {
        Element tcs_elem = doc.createElement("genericConstraints");
        for (Type tc : tp.getBounds()) {
          if (!tc.equals(Object.class))
          {
            Element tc_elem = doc.createElement("genericConstraint");
            Class tcc = (tc instanceof Class) ? (Class)tc : null;
            ParameterizedType pt = (tc instanceof ParameterizedType) ? (ParameterizedType)tc : null;
            if (tcc != null) {
              tc_elem.setAttribute("type", tcc.getName());
            } else if (pt != null) {
              tc_elem.setAttribute("type", getGenericTypeName(pt));
            } else if ((tc instanceof TypeVariable)) {
              tc_elem.setAttribute("type", ((TypeVariable)tc).getName());
            } else {
              throw new UnsupportedOperationException("internal error: unsupported type of Type " + tc.getClass());
            }
            tcs_elem.appendChild(tc_elem);
          }
        }
        if (tcs_elem != null) {
          tp_elem.appendChild(tcs_elem);
        }
      }
      tps_elem.appendChild(tp_elem);
    }
    return tps_elem;
  }
  
  String getSignature(Method method)
  {
    StringBuffer sig = new StringBuffer();
    sig.append(method.getName());
    for (Class t : method.getParameterTypes())
    {
      sig.append(":");
      sig.append(t.getName());
    }
    return sig.toString();
  }
  
  String getGenericSignature(Method method)
  {
    StringBuffer sig = new StringBuffer();
    sig.append(method.getName());
    for (Type t : getGenericParameterTypes(method))
    {
      sig.append(":");
      sig.append(getGenericTypeName(t));
    }
    return sig.toString();
  }
  
  static String getClassName(Class jclass, boolean isFullname)
  {
    if (jclass.isArray()) {
      return getClassName(jclass.getComponentType(), isFullname) + "[]";
    }
    String qualname = jclass.getName();
    String basename = isFullname ? qualname : qualname.substring(jclass.getPackage().getName().length() + 1, qualname.length());
    return basename.replace("$", ".");
  }
  
  public void appendToDocument(Document doc, Element parent)
  {
    try
    {
      doAppendToDocument(doc, parent);
    }
    catch (Throwable ex)
    {
      ex.printStackTrace();
      System.err.println("warning J2XA006: missing class error was raised while reflecting " + jclass.getName() + " : " + ex.getMessage());
    }
  }
  
  Comparator clscmp = new Comparator()
  {
    public int compare(Class c1, Class c2)
    {
      return c1.getName().compareTo(c2.getName());
    }
  };
  
  boolean isInPublicInheritanceChain(Class cls)
  {
    for (Class c = cls; c != null; c = c.getSuperclass()) {
      if ((c.getModifiers() & 0x1) == 0) {
        return false;
      }
    }
    return true;
  }
  
  void doAppendToDocument(Document doc, Element parent)
  {
    int mods = jclass.getModifiers();
    
    Element e = doc.createElement(jclass.isInterface() ? "interface" : "class");
    if (!jclass.isInterface())
    {
      Type t = getGenericSuperclass(jclass);
      if (t != null) {
        e.setAttribute("extends-generic-aware", getGenericTypeName(t));
      }
      Class t2 = jclass.getSuperclass();
      if (t2 != null) {
        e.setAttribute("extends", getClassName(t2, true));
      }
    }
    String className = getClassName(jclass, false);
    e.setAttribute("name", className);
    e.setAttribute("final", Modifier.isFinal(mods) ? "true" : "false");
    e.setAttribute("static", Modifier.isStatic(mods) ? "true" : "false");
    e.setAttribute("abstract", Modifier.isAbstract(mods) ? "true" : "false");
    e.setAttribute("visibility", Modifier.isProtected(mods) ? "protected" : Modifier.isPublic(mods) ? "public" : "");
    if (is_obfuscated) {
      e.setAttribute("obfuscated", Boolean.toString(is_obfuscated));
    }
    Element typeParameters = getTypeParametersNode(doc, jclass.getTypeParameters());
    if (typeParameters != null) {
      e.appendChild(typeParameters);
    }
    setDeprecatedAttr(e, jclass.getDeclaredAnnotations(), e.getAttribute("name"));
    
    Type[] ifaces = getGenericInterfaces(jclass);
    
    sortTypes(ifaces);
    for (Type iface : ifaces)
    {
      Element iface_elem = doc.createElement("implements");
      if ((iface instanceof Class))
      {
        iface_elem.setAttribute("name", getClassName((Class)iface, true));
      }
      else if ((iface instanceof ParameterizedType))
      {
        ParameterizedType pt = (ParameterizedType)iface;
        if ((pt.getRawType() instanceof Class)) {
          iface_elem.setAttribute("name", getClassName((Class)pt.getRawType(), true));
        }
      }
      iface_elem.setAttribute("name-generic-aware", getGenericTypeName(iface));
      iface_elem.appendChild(doc.createTextNode("\n"));
      e.appendChild(iface_elem);
    }
    for (Constructor ctor : jclass.getDeclaredConstructors()) {
      appendCtor(ctor, doc, e);
    }
    Class base_class = jclass.getSuperclass();
    Map<String, Method> methods = new HashMap();
    for (Method method : jclass.getDeclaredMethods()) {
      if ((!method.isSynthetic()) || (!isInPublicInheritanceChain(jclass)))
      {
        int mmods = method.getModifiers();
        
        int rtmods = method.getReturnType().getModifiers();
        if ((Modifier.isPublic(rtmods)) || (Modifier.isProtected(rtmods)))
        {
          boolean nonPublic = false;
          Class[] ptypes = method.getParameterTypes();
          for (int pidx = 0; pidx < ptypes.length; pidx++)
          {
            int ptmods = ptypes[pidx].getModifiers();
            if ((!Modifier.isPublic(ptmods)) && (!Modifier.isProtected(ptmods))) {
              nonPublic = true;
            }
          }
          if (!nonPublic)
          {
            if ((base_class != null) && (!Modifier.isFinal(mmods)))
            {
              Method base_method = null;
              Class ancestor = base_class;
              while ((ancestor != null) && (base_method == null))
              {
                try
                {
                  base_method = ancestor.getDeclaredMethod(method.getName(), method.getParameterTypes());
                }
                catch (Exception ex) {}
                ancestor = ancestor.getSuperclass();
              }
              if (base_method != null)
              {
                int base_mods = base_method.getModifiers();
                int base_decl_class_mods = base_method.getDeclaringClass().getModifiers();
                if ((!Modifier.isStatic(base_mods)) && (!Modifier.isAbstract(base_mods)) && (Modifier.isPublic(mmods) == Modifier.isPublic(base_mods)) && (Modifier.isPublic(base_decl_class_mods)) && 
                
                  ((!Modifier.isAbstract(mmods)) || (method.getName().equals("finalize"))) && (
                  
                  (!method.getName().equals("put")) || (!jclass.getName().equals("java.security.Provider")))) {
                  continue;
                }
              }
            }
            String key = getGenericSignature(method);
            if (methods.containsKey(key))
            {
              Type method_type = getGenericReturnType(method);
              Method hashed = (Method)methods.get(key);
              Type hashed_type = getGenericReturnType(hashed);
              Class mret = (method_type instanceof Class) ? (Class)method_type : null;
              Class hret = (hashed_type instanceof Class) ? (Class)hashed_type : null;
              if ((mret == null) || ((hret != null) && (hret.isAssignableFrom(mret))))
              {
                methods.put(key, method);
              }
              else if ((hret != null) && (!mret.isAssignableFrom(hret)))
              {
                System.err.print("warning J2XA007: method collision: " + jclass.getName() + "." + key);
                System.err.println("   " + getGenericReturnType(hashed).toString() + " ----- " + getGenericReturnType(method).toString());
              }
            }
            else
            {
              methods.put(key, method);
            }
          }
        }
      }
    }
    ArrayList<String> sigs = new ArrayList(methods.keySet());
    Collections.sort(sigs);
    for (String sig : sigs) {
      appendMethod((Method)methods.get(sig), doc, e);
    }
    Field[] fields = getDeclaredFields();
    sortFields(fields);
    for (Field field : fields) {
      appendField(field, (FieldNode)asmFields.get(field.getName()), doc, e);
    }
    parent.appendChild(e);
  }
  
  static final Field[] empty_array = new Field[0];
  
  Field[] getDeclaredFields()
  {
    try
    {
      return jclass.getDeclaredFields();
    }
    catch (NoClassDefFoundError ex)
    {
      List<Field> l = new ArrayList();
      for (FieldNode fn : asm.fields) {
        try
        {
          l.add(jclass.getField(name));
        }
        catch (NoClassDefFoundError exx) {}catch (NoSuchFieldException exx) {}
      }
      return (Field[])l.toArray(empty_array);
    }
  }
  
  void sortFields(Field[] fields)
  {
    Arrays.sort(fields, new Comparator()
    {
      public int compare(Field f1, Field f2)
      {
        return f1.getName().compareTo(f2.getName());
      }
      
      public boolean equals(Object obj)
      {
        return obj == this;
      }
    });
  }
  
  public static String getGenericTypeName(Type type)
  {
    if ((type instanceof Class))
    {
      String name = ((Class)type).getName();
      if (name.charAt(0) == '[')
      {
        String suffix = "";
        while (name.charAt(0) == '[')
        {
          name = name.substring(1);
          suffix = suffix + "[]";
        }
        if (name.equals("B")) {
          return "byte" + suffix;
        }
        if (name.equals("C")) {
          return "char" + suffix;
        }
        if (name.equals("D")) {
          return "double" + suffix;
        }
        if (name.equals("I")) {
          return "int" + suffix;
        }
        if (name.equals("F")) {
          return "float" + suffix;
        }
        if (name.equa
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

Further reading...

For more information on Java 1.5 Tiger, you may find Java 1.5 Tiger, A developer's Notebook by D. Flanagan and B. McLaughlin from O'Reilly of interest.

New!JAR listings


Copyright 2006-2017. Infinite Loop Ltd