• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

raphw / byte-buddy / #641

19 Aug 2024 10:38PM CUT coverage: 85.389% (-0.06%) from 85.448%
#641

push

raphw
Disable validation for minor breakage of protected API.

28759 of 33680 relevant lines covered (85.39%)

0.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.02
/byte-buddy-dep/src/main/java/net/bytebuddy/ClassFileVersion.java
1
/*
2
 * Copyright 2014 - Present Rafael Winterhalter
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package net.bytebuddy;
17

18
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19
import net.bytebuddy.build.AccessControllerPlugin;
20
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
21
import net.bytebuddy.description.type.TypeDescription;
22
import net.bytebuddy.dynamic.ClassFileLocator;
23
import net.bytebuddy.utility.OpenedClassReader;
24
import net.bytebuddy.utility.nullability.MaybeNull;
25
import org.objectweb.asm.Opcodes;
26

27
import java.io.IOException;
28
import java.io.Serializable;
29
import java.lang.reflect.Method;
30
import java.security.PrivilegedAction;
31

32
/**
33
 * A wrapper object for representing a validated class file version in the format that is specified by the
34
 * <a href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html">JVMS</a>.
35
 */
36
public class ClassFileVersion implements Comparable<ClassFileVersion>, Serializable {
37

38
    /**
39
     * The class's serial version UID.
40
     */
41
    private static final long serialVersionUID = 1L;
42

43
    /**
44
     * Returns the minimal version number that is legal.
45
     */
46
    protected static final int BASE_VERSION = 44;
47

48
    /**
49
     * The class file version of Java 1.
50
     */
51
    public static final ClassFileVersion JAVA_V1 = new ClassFileVersion(Opcodes.V1_1);
1✔
52

53
    /**
54
     * The class file version of Java 2.
55
     */
56
    public static final ClassFileVersion JAVA_V2 = new ClassFileVersion(Opcodes.V1_2);
1✔
57

58
    /**
59
     * The class file version of Java 3.
60
     */
61
    public static final ClassFileVersion JAVA_V3 = new ClassFileVersion(Opcodes.V1_3);
1✔
62

63
    /**
64
     * The class file version of Java 4.
65
     */
66
    public static final ClassFileVersion JAVA_V4 = new ClassFileVersion(Opcodes.V1_4);
1✔
67

68
    /**
69
     * The class file version of Java 5.
70
     */
71
    public static final ClassFileVersion JAVA_V5 = new ClassFileVersion(Opcodes.V1_5);
1✔
72

73
    /**
74
     * The class file version of Java 6.
75
     */
76
    public static final ClassFileVersion JAVA_V6 = new ClassFileVersion(Opcodes.V1_6);
1✔
77

78
    /**
79
     * The class file version of Java 7.
80
     */
81
    public static final ClassFileVersion JAVA_V7 = new ClassFileVersion(Opcodes.V1_7);
1✔
82

83
    /**
84
     * The class file version of Java 8.
85
     */
86
    public static final ClassFileVersion JAVA_V8 = new ClassFileVersion(Opcodes.V1_8);
1✔
87

88
    /**
89
     * The class file version of Java 9.
90
     */
91
    public static final ClassFileVersion JAVA_V9 = new ClassFileVersion(Opcodes.V9);
1✔
92

93
    /**
94
     * The class file version of Java 10.
95
     */
96
    public static final ClassFileVersion JAVA_V10 = new ClassFileVersion(Opcodes.V10);
1✔
97

98
    /**
99
     * The class file version of Java 11.
100
     */
101
    public static final ClassFileVersion JAVA_V11 = new ClassFileVersion(Opcodes.V11);
1✔
102

103
    /**
104
     * The class file version of Java 12.
105
     */
106
    public static final ClassFileVersion JAVA_V12 = new ClassFileVersion(Opcodes.V12);
1✔
107

108
    /**
109
     * The class file version of Java 13.
110
     */
111
    public static final ClassFileVersion JAVA_V13 = new ClassFileVersion(Opcodes.V13);
1✔
112

113
    /**
114
     * The class file version of Java 14.
115
     */
116
    public static final ClassFileVersion JAVA_V14 = new ClassFileVersion(Opcodes.V14);
1✔
117

118
    /**
119
     * The class file version of Java 15.
120
     */
121
    public static final ClassFileVersion JAVA_V15 = new ClassFileVersion(Opcodes.V15);
1✔
122

123
    /**
124
     * The class file version of Java 16.
125
     */
126
    public static final ClassFileVersion JAVA_V16 = new ClassFileVersion(Opcodes.V16);
1✔
127

128
    /**
129
     * The class file version of Java 17.
130
     */
131
    public static final ClassFileVersion JAVA_V17 = new ClassFileVersion(Opcodes.V17);
1✔
132

133
    /**
134
     * The class file version of Java 18.
135
     */
136
    public static final ClassFileVersion JAVA_V18 = new ClassFileVersion(Opcodes.V18);
1✔
137

138
    /**
139
     * The class file version of Java 19.
140
     */
141
    public static final ClassFileVersion JAVA_V19 = new ClassFileVersion(Opcodes.V19);
1✔
142

143
    /**
144
     * The class file version of Java 20.
145
     */
146
    public static final ClassFileVersion JAVA_V20 = new ClassFileVersion(Opcodes.V20);
1✔
147

148
    /**
149
     * The class file version of Java 21.
150
     */
151
    public static final ClassFileVersion JAVA_V21 = new ClassFileVersion(Opcodes.V21);
1✔
152

153
    /**
154
     * The class file version of Java 22.
155
     */
156
    public static final ClassFileVersion JAVA_V22 = new ClassFileVersion(Opcodes.V22);
1✔
157

158
    /**
159
     * The class file version of Java 23.
160
     */
161
    public static final ClassFileVersion JAVA_V23 = new ClassFileVersion(Opcodes.V23);
1✔
162

163
    /**
164
     * A version locator for the executing JVM.
165
     */
166
    private static final VersionLocator VERSION_LOCATOR = doPrivileged(VersionLocator.Resolver.INSTANCE);
1✔
167

168
    /**
169
     * The version number that is represented by this class file version instance.
170
     */
171
    private final int versionNumber;
172

173
    /**
174
     * Creates a wrapper for a given minor-major release of the Java class file format.
175
     *
176
     * @param versionNumber The minor-major release number.
177
     */
178
    protected ClassFileVersion(int versionNumber) {
1✔
179
        this.versionNumber = versionNumber;
1✔
180
    }
1✔
181

182
    /**
183
     * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
184
     *
185
     * @param action The action to execute from a privileged context.
186
     * @param <T>    The type of the action's resolved value.
187
     * @return The action's resolved value.
188
     */
189
    @AccessControllerPlugin.Enhance
190
    private static <T> T doPrivileged(PrivilegedAction<T> action) {
191
        return action.run();
×
192
    }
193

194
    /**
195
     * Creates a wrapper for a given minor-major release of the Java class file format.
196
     *
197
     * @param versionNumber The minor-major release number.
198
     * @return A representation of the version number.
199
     */
200
    public static ClassFileVersion ofMinorMajor(int versionNumber) {
201
        ClassFileVersion classFileVersion = new ClassFileVersion(versionNumber);
1✔
202
        if (classFileVersion.getMajorVersion() > 0 && classFileVersion.getMajorVersion() <= BASE_VERSION) {
1✔
203
            throw new IllegalArgumentException("Class version " + versionNumber + " is not valid");
1✔
204
        }
205
        return classFileVersion;
1✔
206
    }
207

208
    /**
209
     * Returns the Java class file by its representation by a version string in accordance to the formats known to <i>javac</i>.
210
     *
211
     * @param javaVersionString The Java version string.
212
     * @return The appropriate class file version.
213
     */
214
    public static ClassFileVersion ofJavaVersionString(String javaVersionString) {
215
        if (javaVersionString.equals("1.1")) {
1✔
216
            return JAVA_V1;
1✔
217
        } else if (javaVersionString.equals("1.2")) {
1✔
218
            return JAVA_V2;
1✔
219
        } else if (javaVersionString.equals("1.3")) {
1✔
220
            return JAVA_V3;
1✔
221
        } else if (javaVersionString.equals("1.4")) {
1✔
222
            return JAVA_V4;
1✔
223
        } else if (javaVersionString.equals("1.5") || javaVersionString.equals("5")) {
1✔
224
            return JAVA_V5;
1✔
225
        } else if (javaVersionString.equals("1.6") || javaVersionString.equals("6")) {
1✔
226
            return JAVA_V6;
1✔
227
        } else if (javaVersionString.equals("1.7") || javaVersionString.equals("7")) {
1✔
228
            return JAVA_V7;
1✔
229
        } else if (javaVersionString.equals("1.8") || javaVersionString.equals("8")) {
1✔
230
            return JAVA_V8;
1✔
231
        } else if (javaVersionString.equals("1.9") || javaVersionString.equals("9")) {
1✔
232
            return JAVA_V9;
1✔
233
        } else if (javaVersionString.equals("1.10") || javaVersionString.equals("10")) {
1✔
234
            return JAVA_V10;
1✔
235
        } else if (javaVersionString.equals("1.11") || javaVersionString.equals("11")) {
1✔
236
            return JAVA_V11;
1✔
237
        } else if (javaVersionString.equals("1.12") || javaVersionString.equals("12")) {
1✔
238
            return JAVA_V12;
1✔
239
        } else if (javaVersionString.equals("1.13") || javaVersionString.equals("13")) {
1✔
240
            return JAVA_V13;
1✔
241
        } else if (javaVersionString.equals("1.14") || javaVersionString.equals("14")) {
1✔
242
            return JAVA_V14;
1✔
243
        } else if (javaVersionString.equals("1.15") || javaVersionString.equals("15")) {
1✔
244
            return JAVA_V15;
1✔
245
        } else if (javaVersionString.equals("1.16") || javaVersionString.equals("16")) {
1✔
246
            return JAVA_V16;
1✔
247
        } else if (javaVersionString.equals("1.17") || javaVersionString.equals("17")) {
1✔
248
            return JAVA_V17;
1✔
249
        } else if (javaVersionString.equals("1.18") || javaVersionString.equals("18")) {
1✔
250
            return JAVA_V18;
1✔
251
        } else if (javaVersionString.equals("1.19") || javaVersionString.equals("19")) {
1✔
252
            return JAVA_V19;
1✔
253
        } else if (javaVersionString.equals("1.20") || javaVersionString.equals("20")) {
1✔
254
            return JAVA_V20;
1✔
255
        } else if (javaVersionString.equals("1.21") || javaVersionString.equals("21")) {
1✔
256
            return JAVA_V21;
1✔
257
        } else if (javaVersionString.equals("1.22") || javaVersionString.equals("22")) {
1✔
258
            return JAVA_V22;
1✔
259
        } else if (javaVersionString.equals("1.23") || javaVersionString.equals("23")) {
1✔
260
            return JAVA_V23;
1✔
261
        } else {
262
            if (OpenedClassReader.EXPERIMENTAL) {
×
263
                try {
264
                    int version = Integer.parseInt(javaVersionString.startsWith("1.")
×
265
                            ? javaVersionString.substring(2)
×
266
                            : javaVersionString);
267
                    if (version > 0) {
×
268
                        return new ClassFileVersion(BASE_VERSION + version);
×
269
                    }
270
                } catch (NumberFormatException ignored) {
×
271
                }
×
272
            }
273
            throw new IllegalArgumentException("Unknown Java version string: " + javaVersionString);
×
274
        }
275
    }
276

277
    /**
278
     * Creates a class file version for a given major release of Java. Currently, all versions reaching from
279
     * Java 1 to Java 9 are supported.
280
     *
281
     * @param javaVersion The Java version.
282
     * @return A wrapper for the given Java class file version.
283
     */
284
    public static ClassFileVersion ofJavaVersion(int javaVersion) {
285
        switch (javaVersion) {
1✔
286
            case 1:
287
                return JAVA_V1;
1✔
288
            case 2:
289
                return JAVA_V2;
1✔
290
            case 3:
291
                return JAVA_V3;
1✔
292
            case 4:
293
                return JAVA_V4;
1✔
294
            case 5:
295
                return JAVA_V5;
1✔
296
            case 6:
297
                return JAVA_V6;
1✔
298
            case 7:
299
                return JAVA_V7;
1✔
300
            case 8:
301
                return JAVA_V8;
1✔
302
            case 9:
303
                return JAVA_V9;
1✔
304
            case 10:
305
                return JAVA_V10;
1✔
306
            case 11:
307
                return JAVA_V11;
1✔
308
            case 12:
309
                return JAVA_V12;
1✔
310
            case 13:
311
                return JAVA_V13;
1✔
312
            case 14:
313
                return JAVA_V14;
1✔
314
            case 15:
315
                return JAVA_V15;
1✔
316
            case 16:
317
                return JAVA_V16;
1✔
318
            case 17:
319
                return JAVA_V17;
1✔
320
            case 18:
321
                return JAVA_V18;
1✔
322
            case 19:
323
                return JAVA_V19;
1✔
324
            case 20:
325
                return JAVA_V20;
1✔
326
            case 21:
327
                return JAVA_V21;
1✔
328
            case 22:
329
                return JAVA_V22;
1✔
330
            case 23:
331
                return JAVA_V23;
1✔
332
            default:
333
                if (OpenedClassReader.EXPERIMENTAL && javaVersion > 0) {
×
334
                    return new ClassFileVersion(BASE_VERSION + javaVersion);
×
335
                } else {
336
                    throw new IllegalArgumentException("Unknown Java version: " + javaVersion);
×
337
                }
338
        }
339
    }
340

341
    /**
342
     * Returns the latest officially supported Java version when experimental support is not enabled.
343
     *
344
     * @return The latest officially supported Java version.
345
     */
346
    public static ClassFileVersion latest() {
347
        return ClassFileVersion.JAVA_V23;
1✔
348
    }
349

350
    /**
351
     * Finds the highest class file version that is compatible to the current JVM version. Prior to Java 9, this is achieved
352
     * by parsing the {@code java.version} property which is provided by {@link java.lang.System#getProperty(String)}. If the system
353
     * property is not available, an {@link IllegalStateException} is thrown.
354
     *
355
     * @return The currently running Java process's class file version.
356
     */
357
    public static ClassFileVersion ofThisVm() {
358
        return VERSION_LOCATOR.resolve();
1✔
359
    }
360

361
    /**
362
     * Finds the highest class file version that is compatible to the current JVM version. Prior to Java 9, this is achieved
363
     * by parsing the {@code java.version} property which is provided by {@link java.lang.System#getProperty(String)}. If the system
364
     * property is not available, the {@code fallback} version is returned.
365
     *
366
     * @param fallback The version to fallback to if locating a class file version is not possible.
367
     * @return The currently running Java process's class file version or the fallback if locating this version is impossible.
368
     */
369
    @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback.")
370
    public static ClassFileVersion ofThisVm(ClassFileVersion fallback) {
371
        try {
372
            return ofThisVm();
1✔
373
        } catch (Exception ignored) {
×
374
            return fallback;
×
375
        }
376
    }
377

378
    /**
379
     * Extracts a class' class version. The class' byte code is located by querying the {@link ClassLoader} of the class.
380
     *
381
     * @param type The type for which to locate a class file version.
382
     * @return The type's class file version.
383
     * @throws IOException If an error occurs while reading the class file.
384
     */
385
    public static ClassFileVersion of(Class<?> type) throws IOException {
386
        return of(type, ClassFileLocator.ForClassLoader.of(type.getClassLoader()));
1✔
387
    }
388

389
    /**
390
     * Extracts a class' class version.
391
     *
392
     * @param type             The type for which to locate a class file version.
393
     * @param classFileLocator The class file locator to query for a class file.
394
     * @return The type's class file version.
395
     * @throws IOException If an error occurs while reading the class file.
396
     */
397
    public static ClassFileVersion of(Class<?> type, ClassFileLocator classFileLocator) throws IOException {
398
        return of(TypeDescription.ForLoadedType.of(type), classFileLocator);
1✔
399
    }
400

401
    /**
402
     * Extracts a class' class version.
403
     *
404
     * @param typeDescription  The type for which to locate a class file version.
405
     * @param classFileLocator The class file locator to query for a class file.
406
     * @return The type's class file version.
407
     * @throws IOException If an error occurs while reading the class file.
408
     */
409
    public static ClassFileVersion of(TypeDescription typeDescription, ClassFileLocator classFileLocator) throws IOException {
410
        return ofClassFile(classFileLocator.locate(typeDescription.getName()).resolve());
1✔
411
    }
412

413
    /**
414
     * Extracts a class' class version from a class file.
415
     *
416
     * @param binaryRepresentation The class file's binary representation.
417
     * @return The supplied class file's class file version.
418
     */
419
    public static ClassFileVersion ofClassFile(byte[] binaryRepresentation) {
420
        if (binaryRepresentation.length < 7) {
1✔
421
            throw new IllegalArgumentException("Supplied byte array is too short to be a class file with " + binaryRepresentation.length + " byte");
1✔
422
        }
423
        return ofMinorMajor(binaryRepresentation[4] << 24
1✔
424
                | binaryRepresentation[5] << 16
425
                | binaryRepresentation[6] << 8
426
                | binaryRepresentation[7]);
427
    }
428

429
    /**
430
     * Returns the minor-major release number of this class file version.
431
     *
432
     * @return The minor-major release number of this class file version.
433
     */
434
    public int getMinorMajorVersion() {
435
        return versionNumber;
1✔
436
    }
437

438
    /**
439
     * Returns the major version this instance represents.
440
     *
441
     * @return The major version this instance represents.
442
     */
443
    public short getMajorVersion() {
444
        return (short) (versionNumber & 0xFFFF);
1✔
445
    }
446

447
    /**
448
     * Returns the minor version this instance represents.
449
     *
450
     * @return The minor version this instance represents.
451
     */
452
    public short getMinorVersion() {
453
        return (short) (versionNumber >>> 16);
1✔
454
    }
455

456
    /**
457
     * Returns the Java runtime version number of this class file version.
458
     *
459
     * @return The Java runtime version.
460
     */
461
    public int getJavaVersion() {
462
        return getMajorVersion() - BASE_VERSION;
1✔
463
    }
464

465
    /**
466
     * Checks if this class file version is at least as new as the provided version.
467
     *
468
     * @param classFileVersion The version to check against.
469
     * @return {@code true} if this version is at least of the given version.
470
     */
471
    public boolean isAtLeast(ClassFileVersion classFileVersion) {
472
        return compareTo(classFileVersion) > -1;
1✔
473
    }
474

475
    /**
476
     * Checks if this class file version is newer than the provided version.
477
     *
478
     * @param classFileVersion The version to check against.
479
     * @return {@code true} if this version is newer than the provided version.
480
     */
481
    public boolean isGreaterThan(ClassFileVersion classFileVersion) {
482
        return compareTo(classFileVersion) > 0;
1✔
483
    }
484

485
    /**
486
     * Checks if this class file version is at most as new as the provided version.
487
     *
488
     * @param classFileVersion The version to check against.
489
     * @return {@code true} if this version is as most as new as the provided version.
490
     */
491
    public boolean isAtMost(ClassFileVersion classFileVersion) {
492
        return compareTo(classFileVersion) < 1;
1✔
493
    }
494

495
    /**
496
     * Checks if this class file version is older than the provided version.
497
     *
498
     * @param classFileVersion The version to check against.
499
     * @return {@code true} if this version is older than the provided version.
500
     */
501
    public boolean isLessThan(ClassFileVersion classFileVersion) {
502
        return compareTo(classFileVersion) < 0;
1✔
503
    }
504

505
    /**
506
     * Returns this class file version indicating a class using preview features.
507
     *
508
     * @return This class file version but indicating the use of preview features.
509
     */
510
    public ClassFileVersion asPreviewVersion() {
511
        return new ClassFileVersion(versionNumber | Opcodes.V_PREVIEW);
1✔
512
    }
513

514
    /**
515
     * Returns {@code true} if this class file version indicates the use of preview features.
516
     *
517
     * @return {@code true} if this class file version indicates the use of preview features.
518
     */
519
    public boolean isPreviewVersion() {
520
        return (versionNumber & Opcodes.V_PREVIEW) == Opcodes.V_PREVIEW;
1✔
521
    }
522

523
    /**
524
     * {@inheritDoc}
525
     */
526
    public int compareTo(ClassFileVersion other) {
527
        return Integer.signum(getMajorVersion() == other.getMajorVersion()
1✔
528
                ? getMinorVersion() - other.getMinorVersion()
1✔
529
                : getMajorVersion() - other.getMajorVersion());
1✔
530
    }
531

532
    @Override
533
    public int hashCode() {
534
        return versionNumber;
1✔
535
    }
536

537
    @Override
538
    public boolean equals(@MaybeNull Object other) {
539
        if (this == other) {
1✔
540
            return true;
1✔
541
        } else if (other == null || getClass() != other.getClass()) {
1✔
542
            return false;
×
543
        }
544
        return versionNumber == ((ClassFileVersion) other).versionNumber;
1✔
545
    }
546

547
    @Override
548
    public String toString() {
549
        return "Java " + getJavaVersion() + " (" + getMinorMajorVersion() + ")";
1✔
550
    }
551

552
    /**
553
     * A locator for the executing VM's Java version.
554
     */
555
    protected interface VersionLocator {
556

557
        /**
558
         * A suffix that might indicate an early access version of Java.
559
         */
560
        String EARLY_ACCESS = "-ea";
561

562
        /**
563
         * A suffix that might indicate an internal version of Java.
564
         */
565
        String INTERNAL = "-internal";
566

567
        /**
568
         * The property for reading the current VM's Java version.
569
         */
570
        String JAVA_VERSION = "java.version";
571

572
        /**
573
         * Locates the current VM's major version number.
574
         *
575
         * @return The current VM's major version number.
576
         */
577
        ClassFileVersion resolve();
578

579
        /**
580
         * A resolver for the current VM's class file version.
581
         */
582
        enum Resolver implements PrivilegedAction<VersionLocator> {
1✔
583

584
            /**
585
             * The singleton instance.
586
             */
587
            INSTANCE;
1✔
588

589
            /**
590
             * {@inheritDoc}
591
             */
592
            @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback.")
593
            public VersionLocator run() {
594
                try {
595
                    Class<?> type = Class.forName(Runtime.class.getName() + "$Version");
×
596
                    Method method;
597
                    try {
598
                        method = type.getMethod("feature");
×
599
                    } catch (NoSuchMethodException ignored) {
×
600
                        method = type.getMethod("major");
×
601
                    }
×
602
                    return new Resolved(ClassFileVersion.ofJavaVersion((Integer) method.invoke(Runtime.class.getMethod("version").invoke(null))));
×
603
                } catch (Throwable ignored) {
1✔
604
                    try {
605
                        String versionString = System.getProperty(JAVA_VERSION);
1✔
606
                        if (versionString == null) {
1✔
607
                            throw new IllegalStateException("Java version property is not set");
×
608
                        } else if (versionString.equals("0")) { // Used by Android, assume Java 6 defensively.
1✔
609
                            return new Resolved(ClassFileVersion.JAVA_V6);
×
610
                        }
611
                        if (versionString.endsWith(EARLY_ACCESS)) {
1✔
612
                            versionString = versionString.substring(0, versionString.length() - EARLY_ACCESS.length());
×
613
                        } else if (versionString.endsWith(INTERNAL)) {
1✔
614
                            versionString = versionString.substring(0, versionString.length() - INTERNAL.length());
×
615
                        }
616
                        int[] versionIndex = {-1, 0, 0};
1✔
617
                        for (int index = 1; index < 3; index++) {
1✔
618
                            versionIndex[index] = versionString.indexOf('.', versionIndex[index - 1] + 1);
1✔
619
                            if (versionIndex[index] == -1) {
1✔
620
                                throw new IllegalStateException("This JVM's version string does not seem to be valid: " + versionString);
×
621
                            }
622
                        }
623
                        return new Resolved(ClassFileVersion.ofJavaVersion(Integer.parseInt(versionString.substring(versionIndex[1] + 1, versionIndex[2]))));
1✔
624
                    } catch (Throwable throwable) {
×
625
                        return new Unresolved(throwable.getMessage());
×
626
                    }
627
                }
628
            }
629
        }
630

631
        /**
632
         * A version locator for a resolved class file version.
633
         */
634
        @HashCodeAndEqualsPlugin.Enhance
635
        class Resolved implements VersionLocator {
636

637
            /**
638
             * The resolved class file version.
639
             */
640
            private final ClassFileVersion classFileVersion;
641

642
            /**
643
             * Creates a new resolved version locator.
644
             *
645
             * @param classFileVersion The resolved class file version.
646
             */
647
            protected Resolved(ClassFileVersion classFileVersion) {
1✔
648
                this.classFileVersion = classFileVersion;
1✔
649
            }
1✔
650

651
            /**
652
             * {@inheritDoc}
653
             */
654
            public ClassFileVersion resolve() {
655
                return classFileVersion;
1✔
656
            }
657
        }
658

659
        /**
660
         * An unresolved version locator.
661
         */
662
        @HashCodeAndEqualsPlugin.Enhance
663
        class Unresolved implements VersionLocator {
664

665
            /**
666
             * The message of the exception that explains the resolution error.
667
             */
668
            private final String message;
669

670
            /**
671
             * Creates an unresolved version locator.
672
             *
673
             * @param message The message of the exception that explains the resolution error.
674
             */
675
            protected Unresolved(String message) {
×
676
                this.message = message;
×
677
            }
×
678

679
            /**
680
             * {@inheritDoc}
681
             */
682
            public ClassFileVersion resolve() {
683
                throw new IllegalStateException("Failed to resolve the class file version of the current VM: " + message);
×
684
            }
685
        }
686
    }
687
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc