InternalTypeUtilities.java revision 1551:f3b883bec2d0
1166065Spjd/* 2166065Spjd * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3166065Spjd * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4166065Spjd * 5166065Spjd * This code is free software; you can redistribute it and/or modify it 6166065Spjd * under the terms of the GNU General Public License version 2 only, as 7166065Spjd * published by the Free Software Foundation. Oracle designates this 8166065Spjd * particular file as subject to the "Classpath" exception as provided 9210984Spjd * by Oracle in the LICENSE file that accompanied this code. 10166065Spjd * 11210984Spjd * This code is distributed in the hope that it will be useful, but WITHOUT 12166065Spjd * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13210984Spjd * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14210984Spjd * version 2 for more details (a copy is included in the LICENSE file that 15210984Spjd * accompanied this code). 16210984Spjd * 17210984Spjd * You should have received a copy of the GNU General Public License version 18210984Spjd * 2 along with this work; if not, write to the Free Software Foundation, 19210984Spjd * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20210984Spjd * 21210984Spjd * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22210984Spjd * or visit www.oracle.com if you need additional information or have any 23210984Spjd * questions. 24210984Spjd */ 25210984Spjdpackage jdk.dynalink.internal; 26210984Spjd 27210984Spjdimport java.util.ArrayList; 28210984Spjdimport java.util.HashSet; 29210984Spjdimport java.util.Iterator; 30210984Spjdimport java.util.List; 31210984Spjdimport java.util.Set; 32210984Spjdimport jdk.dynalink.linker.support.TypeUtilities; 33 34/** 35 * Various static utility methods for testing type relationships; internal to Dynalink. 36 */ 37public class InternalTypeUtilities { 38 private InternalTypeUtilities() { 39 } 40 41 /** 42 * Returns true if either of the types is assignable from the other. 43 * @param c1 one type 44 * @param c2 another type 45 * @return true if either c1 is assignable from c2 or c2 is assignable from c1. 46 */ 47 public static boolean areAssignable(final Class<?> c1, final Class<?> c2) { 48 return c1.isAssignableFrom(c2) || c2.isAssignableFrom(c1); 49 } 50 51 /** 52 * Return true if it is safe to strongly reference a class from the referred 53 * class loader from a class associated with the referring class loader 54 * without risking a class loader memory leak. Generally, it is only safe 55 * to reference classes from the same or ancestor class loader. {@code null} 56 * indicates the system class loader; classes from it can always be 57 * directly referenced, and it can only directly reference classes from 58 * itself. This method can be used by language runtimes to ensure they are 59 * using weak references in their linkages when they need to link to methods 60 * in unrelated class loaders. 61 * 62 * @param referrerLoader the referrer class loader. 63 * @param referredLoader the referred class loader 64 * @return true if it is safe to strongly reference the class from referred 65 * in referred. 66 * @throws SecurityException if the caller does not have the 67 * {@code RuntimePermission("getClassLoader")} permission and the method 68 * needs to traverse the parent class loader chain. 69 */ 70 public static boolean canReferenceDirectly(final ClassLoader referrerLoader, final ClassLoader referredLoader) { 71 if(referredLoader == null) { 72 // Can always refer directly to a system class 73 return true; 74 } 75 if(referrerLoader == null) { 76 // System classes can't refer directly to any non-system class 77 return false; 78 } 79 // Otherwise, can only refer directly to classes residing in same or 80 // parent class loader. 81 82 ClassLoader referrer = referrerLoader; 83 do { 84 if(referrer == referredLoader) { 85 return true; 86 } 87 referrer = referrer.getParent(); 88 } while(referrer != null); 89 return false; 90 } 91 92 /** 93 * Given two types represented by c1 and c2, returns a type that is their 94 * most specific common supertype for purposes of lossless conversions. 95 * 96 * @param c1 one type 97 * @param c2 another type 98 * @return their most common superclass or superinterface for purposes of 99 * lossless conversions. If they have several unrelated superinterfaces as 100 * their most specific common type, or the types themselves are completely 101 * unrelated interfaces, {@link java.lang.Object} is returned. 102 */ 103 public static Class<?> getCommonLosslessConversionType(final Class<?> c1, final Class<?> c2) { 104 if(c1 == c2) { 105 return c1; 106 } else if (c1 == void.class || c2 == void.class) { 107 return Object.class; 108 } else if(TypeUtilities.isConvertibleWithoutLoss(c2, c1)) { 109 return c1; 110 } else if(TypeUtilities.isConvertibleWithoutLoss(c1, c2)) { 111 return c2; 112 } else if(c1.isPrimitive() && c2.isPrimitive()) { 113 if((c1 == byte.class && c2 == char.class) || (c1 == char.class && c2 == byte.class)) { 114 // byte + char = int 115 return int.class; 116 } else if((c1 == short.class && c2 == char.class) || (c1 == char.class && c2 == short.class)) { 117 // short + char = int 118 return int.class; 119 } else if((c1 == int.class && c2 == float.class) || (c1 == float.class && c2 == int.class)) { 120 // int + float = double 121 return double.class; 122 } 123 } 124 // For all other cases. This will handle long + (float|double) = Number case as well as boolean + anything = Object case too. 125 return getMostSpecificCommonTypeUnequalNonprimitives(c1, c2); 126 } 127 128 private static Class<?> getMostSpecificCommonTypeUnequalNonprimitives(final Class<?> c1, final Class<?> c2) { 129 final Class<?> npc1 = c1.isPrimitive() ? TypeUtilities.getWrapperType(c1) : c1; 130 final Class<?> npc2 = c2.isPrimitive() ? TypeUtilities.getWrapperType(c2) : c2; 131 final Set<Class<?>> a1 = getAssignables(npc1, npc2); 132 final Set<Class<?>> a2 = getAssignables(npc2, npc1); 133 a1.retainAll(a2); 134 if(a1.isEmpty()) { 135 // Can happen when at least one of the arguments is an interface, 136 // as they don't have Object at the root of their hierarchy. 137 return Object.class; 138 } 139 // Gather maximally specific elements. Yes, there can be more than one 140 // thank to interfaces. I.e., if you call this method for String.class 141 // and Number.class, you'll have Comparable, Serializable, and Object 142 // as maximal elements. 143 final List<Class<?>> max = new ArrayList<>(); 144 outer: for(final Class<?> clazz: a1) { 145 for(final Iterator<Class<?>> maxiter = max.iterator(); maxiter.hasNext();) { 146 final Class<?> maxClazz = maxiter.next(); 147 if(TypeUtilities.isSubtype(maxClazz, clazz)) { 148 // It can't be maximal, if there's already a more specific 149 // maximal than it. 150 continue outer; 151 } 152 if(TypeUtilities.isSubtype(clazz, maxClazz)) { 153 // If it's more specific than a currently maximal element, 154 // that currently maximal is no longer a maximal. 155 maxiter.remove(); 156 } 157 } 158 // If we get here, no current maximal is more specific than the 159 // current class, so it is considered maximal as well 160 max.add(clazz); 161 } 162 if(max.size() > 1) { 163 return Object.class; 164 } 165 return max.get(0); 166 } 167 168 private static Set<Class<?>> getAssignables(final Class<?> c1, final Class<?> c2) { 169 final Set<Class<?>> s = new HashSet<>(); 170 collectAssignables(c1, c2, s); 171 return s; 172 } 173 174 private static void collectAssignables(final Class<?> c1, final Class<?> c2, final Set<Class<?>> s) { 175 if(c1.isAssignableFrom(c2)) { 176 s.add(c1); 177 } 178 final Class<?> sc = c1.getSuperclass(); 179 if(sc != null) { 180 collectAssignables(sc, c2, s); 181 } 182 final Class<?>[] itf = c1.getInterfaces(); 183 for(int i = 0; i < itf.length; ++i) { 184 collectAssignables(itf[i], c2, s); 185 } 186 } 187} 188