Advertisement
PaleoCrafter

Untitled

Sep 4th, 2014
265
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 8.18 KB | None | 0 0
  1. package de.mineformers.core.asm.util;
  2.  
  3. import com.google.common.cache.CacheBuilder;
  4. import com.google.common.cache.CacheLoader;
  5. import com.google.common.cache.LoadingCache;
  6. import com.google.common.collect.ImmutableSet;
  7. import com.google.common.collect.Sets;
  8. import org.objectweb.asm.Type;
  9. import org.objectweb.asm.tree.ClassNode;
  10.  
  11. import java.util.Arrays;
  12. import java.util.Collection;
  13. import java.util.List;
  14. import java.util.Set;
  15. import java.util.concurrent.TimeUnit;
  16.  
  17. import static org.objectweb.asm.Opcodes.*;
  18.  
  19. /**
  20.  * Some information about a class, obtain via {@link ClassInfo#of(org.objectweb.asm.tree.ClassNode)}
  21.  * Licensed under LGPL v3
  22.  *
  23.  * @author diesieben07
  24.  */
  25. public abstract class ClassInfo
  26. {
  27.     private static LoadingCache<String, ClassInfo> cache;
  28.  
  29.     static
  30.     {
  31.         cache = CacheBuilder.newBuilder()
  32.                 .concurrencyLevel(1)
  33.                 .expireAfterAccess(3, TimeUnit.MINUTES)
  34.                 .build(new ClassInfoLoader());
  35.     }
  36.  
  37.     private Set<String> supers;
  38.     private ClassInfo zuper;
  39.  
  40.     /**
  41.      * create a {@link ClassInfo} representing the given Class
  42.      *
  43.      * @param clazz the Class
  44.      * @return a ClassInfo
  45.      */
  46.     public static ClassInfo of(Class<?> clazz)
  47.     {
  48.         return new ClassInfoFromClazz(clazz);
  49.     }
  50.  
  51.     /**
  52.      * create a {@link ClassInfo} representing the given ClassNode
  53.      *
  54.      * @param clazz the ClassNode
  55.      * @return a ClassInfo
  56.      */
  57.     public static ClassInfo of(ClassNode clazz)
  58.     {
  59.         return new ClassInfoFromNode(clazz);
  60.     }
  61.  
  62.     public static ClassInfo of(Type type)
  63.     {
  64.         switch (type.getSort())
  65.         {
  66.             case Type.ARRAY:
  67.             case Type.OBJECT:
  68.                 // Type.getClassName incorrectly returns something like "java.lang.Object[][]" instead of "[[Ljava.lang.Object"
  69.                 // so we have to convert the internal name (which is corrent) manually
  70.                 return cache.getUnchecked(SevenASMUtils.binaryName(type.getInternalName()));
  71.             case Type.METHOD:
  72.                 throw new IllegalArgumentException("Invalid Type!");
  73.             default:
  74.                 // primitives
  75.                 return of(type.getClassName());
  76.         }
  77.     }
  78.  
  79.     /**
  80.      * <p>create a {@link ClassInfo} representing the given class.</p>
  81.      * <p>This method will not load any classes through the ClassLoader directly, but instead use the ASM library to analyze the raw class bytes.</p>
  82.      *
  83.      * @param className the class
  84.      * @return a ClassInfo
  85.      */
  86.     public static ClassInfo of(String className)
  87.     {
  88.         return cache.getUnchecked(SevenASMUtils.binaryName(className));
  89.     }
  90.  
  91.     private static ClassInfo create(String className)
  92.     {
  93.         switch (className)
  94.         {
  95.             case "boolean":
  96.                 return of(boolean.class);
  97.             case "byte":
  98.                 return of(byte.class);
  99.             case "short":
  100.                 return of(short.class);
  101.             case "int":
  102.                 return of(int.class);
  103.             case "long":
  104.                 return of(long.class);
  105.             case "float":
  106.                 return of(float.class);
  107.             case "double":
  108.                 return of(double.class);
  109.             case "char":
  110.                 return of(char.class);
  111.             default:
  112.                 if (className.indexOf('[') >= 0)
  113.                 {
  114.                     // array classes should always be accessible via Class.forName
  115.                     // without loading the element-type class (Object[].class doesn't load Object.class)
  116.                     return forceLoad(className);
  117.                 }
  118.                 else
  119.                 {
  120.                     return ofObject(className);
  121.                 }
  122.         }
  123.     }
  124.  
  125.     private static ClassInfo ofObject(String className)
  126.     {
  127.         return forceLoad(className);
  128.     }
  129.  
  130.     private static ClassInfo forceLoad(String className)
  131.     {
  132.         try
  133.         {
  134.             return of(Class.forName(className));
  135.         }
  136.         catch (Exception e)
  137.         {
  138.             e.printStackTrace();
  139.         }
  140.         return null;
  141.     }
  142.  
  143.     /**
  144.      * a collection of internal names, representing the interfaces directly implemented by this class
  145.      *
  146.      * @return the interfaces implemented by this class
  147.      */
  148.     public abstract Collection<String> interfaces();
  149.  
  150.     /**
  151.      * get the internal name of the superclass of this class
  152.      *
  153.      * @return the superclass, or null if this ClassInfo is an interface or represents java/lang/Object
  154.      */
  155.     public abstract String superName();
  156.  
  157.     /**
  158.      * get the internal name of this class
  159.      *
  160.      * @return the internal name
  161.      */
  162.     public abstract String internalName();
  163.  
  164.     public ClassInfo superclass()
  165.     {
  166.         if (zuper != null)
  167.         {
  168.             return zuper;
  169.         }
  170.         if (superName() == null)
  171.         {
  172.             return null;
  173.         }
  174.         return (zuper = of(superName()));
  175.     }
  176.  
  177.     public boolean isAssignableFrom(ClassInfo child)
  178.     {
  179.         // some cheap tests first
  180.         if (child.internalName().equals("java/lang/Object"))
  181.         {
  182.             // Object is only assignable to itself
  183.             return internalName().equals("java/lang/Object");
  184.         }
  185.         if (internalName().equals("java/lang/Object") // everything is assignable to Object
  186.                 || child.internalName().equals(internalName()) // we are the same
  187.                 || internalName().equals(child.superName()) // we are the superclass of child
  188.                 || child.interfaces().contains(internalName()))
  189.         { // we are an interface that child implements
  190.             return true;
  191.         }
  192.  
  193.         // if we are a class no interface can be cast to us
  194.         if (!isInterface() && child.isInterface())
  195.         {
  196.             return false;
  197.         }
  198.         // need to compute supers now
  199.         return child.getSupers().contains(internalName());
  200.     }
  201.  
  202.     private Set<String> buildSupers()
  203.     {
  204.         Set<String> set = Sets.newHashSet();
  205.         if (superName() != null)
  206.         {
  207.             set.add(superName());
  208.             set.addAll(superclass().getSupers());
  209.         }
  210.         for (String iface : interfaces())
  211.         {
  212.             if (set.add(iface))
  213.             {
  214.                 set.addAll(of(iface).getSupers());
  215.             }
  216.         }
  217.         // use immutable set to reduce memory footprint and potentially increase performance
  218.         return ImmutableSet.copyOf(set);
  219.     }
  220.  
  221.     public Set<String> getSupers()
  222.     {
  223.         return supers == null ? (supers = buildSupers()) : supers;
  224.     }
  225.  
  226.     /**
  227.      * get all Modifiers present on this class. Equivalent to {@link Class#getModifiers()}
  228.      *
  229.      * @return the modifiers
  230.      */
  231.     public abstract int modifiers();
  232.  
  233.     @Override
  234.     public boolean equals(Object o)
  235.     {
  236.         return this == o || o instanceof ClassInfo && internalName().equals(((ClassInfo) o).internalName());
  237.  
  238.     }
  239.  
  240.     @Override
  241.     public int hashCode()
  242.     {
  243.         return internalName().hashCode();
  244.     }
  245.  
  246.     public boolean isEnum()
  247.     {
  248.         return hasModifier(ACC_ENUM) && superName().equals("java/lang/Enum");
  249.     }
  250.  
  251.     public boolean isAbstract()
  252.     {
  253.         return hasModifier(ACC_ABSTRACT);
  254.     }
  255.  
  256.     public boolean isInterface()
  257.     {
  258.         return hasModifier(ACC_INTERFACE);
  259.     }
  260.  
  261.     public boolean isArray()
  262.     {
  263.         return getDimensions() > 0;
  264.     }
  265.  
  266.     public abstract int getDimensions();
  267.  
  268.     public boolean hasModifier(int mod)
  269.     {
  270.         return (modifiers() & mod) == mod;
  271.     }
  272.  
  273.     abstract public List<Type[]> constructorTypes();
  274.  
  275.     public boolean hasConstructor(Type... parameters)
  276.     {
  277.         for (Type[] params : constructorTypes())
  278.         {
  279.             if (Arrays.equals(params, parameters))
  280.             {
  281.                 return true;
  282.             }
  283.         }
  284.         return false;
  285.     }
  286.  
  287.     private static class ClassInfoLoader extends CacheLoader<String, ClassInfo>
  288.     {
  289.  
  290.         @Override
  291.         public ClassInfo load(String clazz)
  292.         {
  293.             return ClassInfo.create(clazz);
  294.         }
  295.  
  296.     }
  297.  
  298. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement