|
28 | 28 | * @author Jerry Lee (oldratlee at gmail dot com) |
29 | 29 | * @see InetAddress |
30 | 30 | * @see InetAddress#addressCache |
| 31 | + * @see InetAddress.CacheEntry |
31 | 32 | * @see InetAddress#cacheInitIfNeeded() |
32 | 33 | * @see InetAddress#cacheAddresses(String, InetAddress[], boolean) |
33 | 34 | */ |
@@ -61,7 +62,17 @@ static Object createCacheEntry(String host, String[] ips, long expiration) |
61 | 62 | IllegalAccessException, InvocationTargetException, InstantiationException { |
62 | 63 | String className = "java.net.InetAddress$CacheEntry"; |
63 | 64 | Class<?> clazz = Class.forName(className); |
64 | | - Constructor<?> constructor = clazz.getDeclaredConstructor(InetAddress[].class, long.class); |
| 65 | + |
| 66 | + // InetAddress.CacheEntry has only a constructor: |
| 67 | + // - for jdk 6, constructor signature is CacheEntry(Object address, long expiration) |
| 68 | + // - for jdk 7+, constructor signature is CacheEntry(InetAddress[] addresses, long expiration) |
| 69 | + // code in jdk 6: |
| 70 | + // http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b27/java/net/InetAddress.java#InetAddress.CacheEntry |
| 71 | + // code in jdk 7: |
| 72 | + // http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/net/InetAddress.java#InetAddress.CacheEntry |
| 73 | + // code in jdk 8: |
| 74 | + // http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/net/InetAddress.java#InetAddress.CacheEntry |
| 75 | + Constructor<?> constructor = clazz.getDeclaredConstructors()[0]; |
65 | 76 | constructor.setAccessible(true); |
66 | 77 | return constructor.newInstance(toInetAddressArray(host, ips), expiration); |
67 | 78 | } |
@@ -90,9 +101,11 @@ static Object getAddressCacheFieldOfInetAddress() |
90 | 101 | throws NoSuchFieldException, IllegalAccessException { |
91 | 102 | if (ADDRESS_CACHE == null) { |
92 | 103 | synchronized (InetAddressCacheUtil.class) { |
93 | | - final Field cacheField = InetAddress.class.getDeclaredField("addressCache"); |
94 | | - cacheField.setAccessible(true); |
95 | | - ADDRESS_CACHE = cacheField.get(InetAddress.class); |
| 104 | + if (ADDRESS_CACHE == null) { // double check |
| 105 | + final Field cacheField = InetAddress.class.getDeclaredField("addressCache"); |
| 106 | + cacheField.setAccessible(true); |
| 107 | + ADDRESS_CACHE = cacheField.get(InetAddress.class); |
| 108 | + } |
96 | 109 | } |
97 | 110 | } |
98 | 111 | return ADDRESS_CACHE; |
@@ -150,17 +163,45 @@ public static List<DnsCacheEntry> listInetAddressCache() |
150 | 163 | return list; |
151 | 164 | } |
152 | 165 |
|
| 166 | + |
| 167 | + static volatile Field expirationFieldOfInetAddress$CacheEntry = null; |
| 168 | + static volatile Field addressesFieldOfInetAddress$CacheEntry = null; |
| 169 | + |
153 | 170 | static DnsCacheEntry inetAddress$CacheEntry2DnsCacheEntry(String host, Object entry) |
154 | 171 | throws NoSuchFieldException, IllegalAccessException { |
155 | | - Class<?> cacheEntryClass = entry.getClass(); |
156 | | - |
157 | | - Field expirationField = cacheEntryClass.getDeclaredField("expiration"); |
158 | | - expirationField.setAccessible(true); |
159 | | - long expiration = (Long) expirationField.get(entry); |
| 172 | + if (expirationFieldOfInetAddress$CacheEntry == null || addressesFieldOfInetAddress$CacheEntry == null) { |
| 173 | + synchronized (InetAddressCacheUtil.class) { |
| 174 | + if (expirationFieldOfInetAddress$CacheEntry == null) { // double check |
| 175 | + Class<?> cacheEntryClass = entry.getClass(); |
| 176 | + // InetAddress.CacheEntry has 2 filed: |
| 177 | + // - for jdk 6, address and expiration |
| 178 | + // - for jdk 7+, addresses(*renamed* from 6!) and expiration |
| 179 | + // code in jdk 6: |
| 180 | + // http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b27/java/net/InetAddress.java#InetAddress.CacheEntry |
| 181 | + // code in jdk 7: |
| 182 | + // http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/net/InetAddress.java#InetAddress.CacheEntry |
| 183 | + // code in jdk 8: |
| 184 | + // http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/net/InetAddress.java#InetAddress.CacheEntry |
| 185 | + final Field[] fields = cacheEntryClass.getDeclaredFields(); |
| 186 | + for (Field field : fields) { |
| 187 | + final String name = field.getName(); |
| 188 | + if (name.equals("expiration")) { |
| 189 | + field.setAccessible(true); |
| 190 | + expirationFieldOfInetAddress$CacheEntry = field; |
| 191 | + } else if (name.startsWith("address")) { // use startWith so works for jdk 6 and jdk 7+ |
| 192 | + field.setAccessible(true); |
| 193 | + addressesFieldOfInetAddress$CacheEntry = field; |
| 194 | + } else { |
| 195 | + throw new IllegalStateException("JDK add new Field " + name + |
| 196 | + " for class InetAddress.CacheEntry, report bug for dns-cache-manipulator lib!"); |
| 197 | + } |
| 198 | + } |
| 199 | + } |
| 200 | + } |
| 201 | + } |
160 | 202 |
|
161 | | - Field addressesField = cacheEntryClass.getDeclaredField("addresses"); |
162 | | - addressesField.setAccessible(true); |
163 | | - InetAddress[] addresses = (InetAddress[]) addressesField.get(entry); |
| 203 | + long expiration = (Long) expirationFieldOfInetAddress$CacheEntry.get(entry); |
| 204 | + InetAddress[] addresses = (InetAddress[]) addressesFieldOfInetAddress$CacheEntry.get(entry); |
164 | 205 |
|
165 | 206 | String[] ips = new String[addresses.length]; |
166 | 207 | for (int i = 0; i < addresses.length; i++) { |
|
0 commit comments