Skip to content

Commit 568a966

Browse files
jmehrenslukasj
authored andcommitted
MethodHandles only supported in Android API version 26
1 parent 9f4c575 commit 568a966

File tree

2 files changed

+93
-68
lines changed

2 files changed

+93
-68
lines changed

mail/src/main/java/com/sun/mail/util/logging/LogManagerProperties.java

Lines changed: 90 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@
1717
package com.sun.mail.util.logging;
1818

1919
import java.io.*;
20-
import java.lang.invoke.MethodHandle;
21-
import java.lang.invoke.MethodHandles;
22-
import java.lang.invoke.MethodHandles.Lookup;
23-
import java.lang.invoke.MethodType;
2420
import java.lang.reflect.InvocationTargetException;
2521
import java.lang.reflect.Method;
2622
import java.lang.reflect.Modifier;
@@ -60,71 +56,74 @@ final class LogManagerProperties extends Properties {
6056
*/
6157
private static final long serialVersionUID = -2239983349056806252L;
6258

63-
/**
64-
* Public lookup for method handles.
65-
*/
66-
private static final Lookup LOOKUP = MethodHandles.publicLookup();
67-
6859
/**
6960
* Holds the method used to get the LogRecord instant if running on JDK 9 or
7061
* later.
7162
*/
72-
private static final MethodHandle LR_GET_INSTANT;
63+
private static final Method LR_GET_INSTANT;
7364

7465
/**
7566
* Holds the method used to get the long thread id if running on JDK 16 or
7667
* later.
7768
*/
78-
private static final MethodHandle LR_GET_LONG_TID;
69+
private static final Method LR_GET_LONG_TID;
7970

8071
/**
8172
* Holds the method used to get the default time zone if running on JDK 9 or
8273
* later.
8374
*/
84-
private static final MethodHandle ZI_SYSTEM_DEFAULT;
75+
private static final Method ZI_SYSTEM_DEFAULT;
8576

8677
/**
8778
* Holds the method used to convert and instant to a zoned date time if
8879
* running on JDK 9 later.
8980
*/
90-
private static final MethodHandle ZDT_OF_INSTANT;
91-
81+
private static final Method ZDT_OF_INSTANT;
9282

83+
/**
84+
* MethodHandle is available starting at JDK7 and Andriod API 26.
85+
*/
9386
static { //Added in JDK16 see JDK-8245302
94-
MethodHandle lrgltid = null;
87+
Method lrtid = null;
9588
try {
96-
lrgltid = LOOKUP.findVirtual(LogRecord.class,
97-
"getLongThreadID", MethodType.methodType(long.class));
89+
lrtid = LogRecord.class.getMethod("getLongThreadID");
9890
} catch (final RuntimeException ignore) {
9991
} catch (final Exception ignore) { //No need for specific catch.
10092
} catch (final LinkageError ignore) {
10193
}
102-
LR_GET_LONG_TID = lrgltid;
94+
LR_GET_LONG_TID = lrtid;
10395
}
10496

105-
static { //Added in JDK 9 see JDK-8072645
106-
MethodHandle lrgi = null;
107-
MethodHandle zisd = null;
108-
MethodHandle zdtoi = null;
97+
static {
98+
Method lrgi = null;
99+
Method zisd = null;
100+
Method zdtoi = null;
109101
try {
110-
lrgi = LOOKUP.findVirtual(LogRecord.class, "getInstant",
111-
MethodType.methodType(findClass("java.time.Instant")));
112-
113-
zisd = LOOKUP.findStatic(findClass("java.time.ZoneId"),
114-
"systemDefault",
115-
MethodType.methodType(findClass("java.time.ZoneId")));
116-
117-
zdtoi = LOOKUP.findStatic(findClass("java.time.ZonedDateTime"),
118-
"ofInstant",
119-
MethodType.methodType(findClass("java.time.ZonedDateTime"),
120-
findClass("java.time.Instant"),
121-
findClass("java.time.ZoneId")));
102+
lrgi = LogRecord.class.getMethod("getInstant");
103+
assert Comparable.class
104+
.isAssignableFrom(lrgi.getReturnType()) : lrgi;
105+
zisd = findClass("java.time.ZoneId")
106+
.getMethod("systemDefault");
107+
if (!Modifier.isStatic(zisd.getModifiers())) {
108+
zisd = null;
109+
throw new NoSuchMethodException(zisd.toString());
110+
}
111+
112+
zdtoi = findClass("java.time.ZonedDateTime")
113+
.getMethod("ofInstant", findClass("java.time.Instant"),
114+
findClass("java.time.ZoneId"));
115+
if (!Modifier.isStatic(zdtoi.getModifiers())
116+
|| !Comparable.class.isAssignableFrom(
117+
zdtoi.getReturnType())) {
118+
zdtoi = null;
119+
throw new NoSuchMethodException(zdtoi.toString());
120+
}
122121
} catch (final RuntimeException ignore) {
123122
} catch (final Exception ignore) { //No need for specific catch.
124123
} catch (final LinkageError ignore) {
125124
} finally {
126125
if (lrgi == null || zisd == null || zdtoi == null) {
127-
lrgi = null;
126+
lrgi = null; //If any are null then clear all.
128127
zisd = null;
129128
zdtoi = null;
130129
}
@@ -322,22 +321,31 @@ static boolean hasLogManager() {
322321
* @throws NullPointerException if record is null.
323322
* @since JavaMail 1.5.6
324323
*/
325-
static Comparable<?> getZonedDateTime(final LogRecord record) {
324+
@SuppressWarnings("UseSpecificCatch")
325+
static Comparable<?> getZonedDateTime(LogRecord record) {
326326
if (record == null) {
327327
throw new NullPointerException();
328328
}
329-
330-
MethodHandle m = ZDT_OF_INSTANT;
329+
final Method m = ZDT_OF_INSTANT;
331330
if (m != null) {
332331
try {
333-
return (Comparable<?>) m.invoke(
332+
return (Comparable<?>) m.invoke((Object) null,
334333
LR_GET_INSTANT.invoke(record),
335-
ZI_SYSTEM_DEFAULT.invoke());
336-
} catch (final RuntimeException | Error e) {
337-
throw e; //Avoid catch all
338-
} catch (final Throwable ute) {
339-
throw new UndeclaredThrowableException(ute);
340-
}
334+
ZI_SYSTEM_DEFAULT.invoke((Object) null));
335+
} catch (final RuntimeException ignore) {
336+
assert LR_GET_INSTANT != null
337+
&& ZI_SYSTEM_DEFAULT != null : ignore;
338+
} catch (final InvocationTargetException ite) {
339+
final Throwable cause = ite.getCause();
340+
if (cause instanceof Error) {
341+
throw (Error) cause;
342+
} else if (cause instanceof RuntimeException) {
343+
throw (RuntimeException) cause;
344+
} else { //Should never happen.
345+
throw new UndeclaredThrowableException(ite);
346+
}
347+
} catch (final Exception ignore) {
348+
}
341349
}
342350
return null;
343351
}
@@ -355,14 +363,21 @@ static Long getLongThreadID(final LogRecord record) {
355363
throw new NullPointerException();
356364
}
357365

358-
final MethodHandle m = LR_GET_LONG_TID;
366+
final Method m = LR_GET_LONG_TID;
359367
if (m != null) {
360368
try {
361-
return (long) m.invoke(record);
362-
} catch (final RuntimeException | Error e) {
363-
throw e;
364-
} catch (final Throwable ute) {
365-
throw new UndeclaredThrowableException(ute);
369+
return (Long) m.invoke(record);
370+
} catch (final InvocationTargetException ite) {
371+
final Throwable cause = ite.getCause();
372+
if (cause instanceof Error) {
373+
throw (Error) cause;
374+
} else if (cause instanceof RuntimeException) {
375+
throw (RuntimeException) cause;
376+
} else { //Should never happen.
377+
throw new UndeclaredThrowableException(ite);
378+
}
379+
} catch (final RuntimeException ignore) {
380+
} catch (final Exception ignore) {
366381
}
367382
}
368383
return null;
@@ -405,9 +420,10 @@ static String getLocalHost(final Object s) throws Exception {
405420
*
406421
* @param value an ISO-8601 duration character sequence.
407422
* @return the number of milliseconds parsed from the duration.
423+
* @throws ArithmeticException if the duration is too large or too small.
408424
* @throws ClassNotFoundException if the java.time classes are not present.
409425
* @throws IllegalAccessException if the method is inaccessible.
410-
* @throws RuntimeException if the method throws an exception.
426+
* @throws InvocationTargetException if the method throws an exception.
411427
* @throws LinkageError if the linkage fails.
412428
* @throws NullPointerException if the given duration is null.
413429
* @throws ExceptionInInitializerError if the static initializer fails.
@@ -421,20 +437,29 @@ static long parseDurationToMillis(final CharSequence value) throws Exception {
421437
if (value == null) {
422438
throw new NullPointerException();
423439
}
424-
425440
try {
426-
Class<?> k = findClass("java.time.Duration");
427-
MethodHandle dp = LOOKUP.findStatic(k, "parse",
428-
MethodType.methodType(k, CharSequence.class));
429-
430-
MethodHandle dtm = LOOKUP.findVirtual(k, "toMillis",
431-
MethodType.methodType(Long.TYPE));
432-
return (long) dtm.invoke(dp.invoke(value));
433-
} catch (final RuntimeException | LinkageError
434-
| ReflectiveOperationException fail) {
435-
throw fail; //avoid catch all
436-
} catch (Throwable cause) {
437-
throw new InvocationTargetException(cause);
441+
final Class<?> k = findClass("java.time.Duration");
442+
final Method parse = k.getMethod("parse", CharSequence.class);
443+
if (!k.isAssignableFrom(parse.getReturnType())
444+
|| !Modifier.isStatic(parse.getModifiers())) {
445+
throw new NoSuchMethodException(parse.toString());
446+
}
447+
448+
final Method toMillis = k.getMethod("toMillis");
449+
if (!Long.TYPE.isAssignableFrom(toMillis.getReturnType())
450+
|| Modifier.isStatic(toMillis.getModifiers())) {
451+
throw new NoSuchMethodException(toMillis.toString());
452+
}
453+
return (Long) toMillis.invoke(parse.invoke(null, value));
454+
} catch (final ExceptionInInitializerError EIIE) {
455+
throw wrapOrThrow(EIIE);
456+
} catch (final InvocationTargetException ite) {
457+
final Throwable cause = ite.getCause();
458+
if (cause instanceof ArithmeticException) {
459+
throw (ArithmeticException) cause;
460+
} else {
461+
throw paramOrError(ite);
462+
}
438463
}
439464
}
440465

mail/src/test/java/com/sun/mail/util/logging/LogManagerPropertiesTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -492,12 +492,12 @@ public void testParseDurationParseException() throws Exception {
492492
fail(Long.toString(ms));
493493
} catch (ClassNotFoundException | NoClassDefFoundError ignore) {
494494
assertFalse(ignore.toString(), hasJavaTimeModule());
495-
} catch (RuntimeException expected) {
495+
} catch (InvocationTargetException expected) {
496+
Throwable dtpe = expected.getCause();
496497
//Allow subclasses of DTPE
497498
Class<?> k = Class.forName(
498499
"java.time.format.DateTimeParseException");
499-
assertTrue(expected.toString(),
500-
k.isAssignableFrom(expected.getClass()));
500+
assertTrue(k.getName(), k.isAssignableFrom(dtpe.getClass()));
501501
}
502502
}
503503

0 commit comments

Comments
 (0)