Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  AccessControlTest.java   Sprache: JAVA

 
/*
 * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */


/* @test
 * @summary test access checking by java.lang.invoke.MethodHandles.Lookup
 * @compile AccessControlTest.java AccessControlTest_subpkg/Acquaintance_remote.java
 * @run testng/othervm test.java.lang.invoke.AccessControlTest
 */


package test.java.lang.invoke;

import java.lang.invoke.*;
import java.lang.reflect.*;
import java.lang.reflect.Modifier;
import java.util.*;
import org.testng.annotations.*;

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodHandles.Lookup.*;
import static java.lang.invoke.MethodType.*;
import static org.testng.Assert.*;

import test.java.lang.invoke.AccessControlTest_subpkg.Acquaintance_remote;


/**
 * Test many combinations of Lookup access and cross-class lookupStatic.
 * @author jrose
 */

public class AccessControlTest {
    static final Class<?> THIS_CLASS = AccessControlTest.class;
    // How much output?
    static int verbosity = 0;
    static {
        String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".verbosity");
        if (vstr == null)
            vstr = System.getProperty(THIS_CLASS.getName()+".verbosity");
        if (vstr != null)  verbosity = Integer.parseInt(vstr);
    }

    private class LookupCase implements Comparable<LookupCase> {
        final Lookup   lookup;
        final Class<?> lookupClass;
        final Class<?> prevLookupClass;
        final int      lookupModes;
        public LookupCase(Lookup lookup) {
            this.lookup = lookup;
            this.lookupClass = lookup.lookupClass();
            this.prevLookupClass = lookup.previousLookupClass();
            this.lookupModes = lookup.lookupModes();

            assert(lookupString().equals(lookup.toString()));
            numberOf(lookupClass().getClassLoader()); // assign CL#
        }
        public LookupCase(Class<?> lookupClass, Class<?> prevLookupClass, int lookupModes) {
            this.lookup = null;
            this.lookupClass = lookupClass;
            this.prevLookupClass = prevLookupClass;
            this.lookupModes = lookupModes;
            numberOf(lookupClass().getClassLoader()); // assign CL#
        }

        public final Class<?> lookupClass()     { return lookupClass; }
        public final Class<?> prevLookupClass() { return prevLookupClass; }
        public final int      lookupModes()     { return lookupModes; }

        public Lookup lookup() { lookup.getClass(); return lookup; }

        @Override
        public int compareTo(LookupCase that) {
            Class<?> c1 = this.lookupClass();
            Class<?> c2 = that.lookupClass();
            Class<?> p1 = this.prevLookupClass();
            Class<?> p2 = that.prevLookupClass();
            if (c1 != c2) {
                int cmp = c1.getName().compareTo(c2.getName());
                if (cmp != 0)  return cmp;
                cmp = numberOf(c1.getClassLoader()) - numberOf(c2.getClassLoader());
                assert(cmp != 0);
                return cmp;
            } else if (p1 != p2){
                if (p1 == null)
                    return 1;
                else if (p2 == null)
                    return -1;
                int cmp = p1.getName().compareTo(p2.getName());
                if (cmp != 0)  return cmp;
                cmp = numberOf(p1.getClassLoader()) - numberOf(p2.getClassLoader());
                assert(cmp != 0);
                return cmp;
            }
            return -(this.lookupModes() - that.lookupModes());
        }

        @Override
        public boolean equals(Object that) {
            return (that instanceof LookupCase && equals((LookupCase)that));
        }
        public boolean equals(LookupCase that) {
            return (this.lookupClass() == that.lookupClass() &&
                    this.prevLookupClass() == that.prevLookupClass() &&
                    this.lookupModes() == that.lookupModes());
        }

        @Override
        public int hashCode() {
            return lookupClass().hashCode() + (lookupModes() * 31);
        }

        /** Simulate all assertions in the spec. for Lookup.toString. */
        private String lookupString() {
            String name = lookupClass.getName();
            if (prevLookupClass != null)
                name += "/" + prevLookupClass.getName();
            String suffix = "";
            if (lookupModes == 0)
                suffix = "/noaccess";
            else if (lookupModes == PUBLIC)
                suffix = "/public";
             else if (lookupModes == UNCONDITIONAL)
                suffix = "/publicLookup";
            else if (lookupModes == (PUBLIC|MODULE))
                suffix = "/module";
            else if (lookupModes == (PUBLIC|PACKAGE)
                     || lookupModes == (PUBLIC|MODULE|PACKAGE))
                suffix = "/package";
            else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE)
                    || lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE))
                suffix = "/private";
            else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE|PROTECTED)
                     || lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED)
                     || lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED|ORIGINAL))
                suffix = "";
            else
                suffix = "/#"+Integer.toHexString(lookupModes);
            return name+suffix;
        }

        /** Simulate all assertions from the spec. for Lookup.in:
         * <hr>
         * Creates a lookup on the specified new lookup class.
         * [A1] The resulting object will report the specified
         * class as its own {@link #lookupClass lookupClass}.
         * [A1-a] However, the resulting {@code Lookup} object is guaranteed
         * to have no more access capabilities than the original.
         * In particular, access capabilities can be lost as follows:<ul>
         * [A2] If the new lookup class is not the same as the old lookup class,
         * then {@link #ORIGINAL ORIGINAL} access is lost.
         * [A3] If the new lookup class is in a different module from the old one,
         * i.e. {@link #MODULE MODULE} access is lost.
         * [A4] If the new lookup class is in a different package
         * than the old one, protected and default (package) members will not be accessible,
         * i.e. {@link #PROTECTED PROTECTED} and {@link #PACKAGE PACKAGE} access are lost.
         * [A5] If the new lookup class is not within the same package member
         * as the old one, private members will not be accessible, and protected members
         * will not be accessible by virtue of inheritance,
         * i.e. {@link #PRIVATE PRIVATE} access is lost.
         * (Protected members may continue to be accessible because of package sharing.)
         * [A6] If the new lookup class is not
         * {@linkplain #accessClass(Class) accessible} to this lookup,
         * then no members, not even public members, will be accessible
         * i.e. all access modes are lost.
         * [A7] If the new lookup class, the old lookup class and the previous lookup class
         * are all in different modules i.e. teleporting to a third module,
         * all access modes are lost.
         * <p>
         * The new previous lookup class is chosen as follows:
         * [A8] If the new lookup object has {@link #UNCONDITIONAL UNCONDITIONAL} bit,
         * the new previous lookup class is {@code null}.
         * [A9] If the new lookup class is in the same module as the old lookup class,
         * the new previous lookup class is the old previous lookup class.
         * [A10] If the new lookup class is in a different module from the old lookup class,
         * the new previous lookup class is the old lookup class.
         *
         * Other than the above cases, the new lookup will have the same
         * access capabilities as the original. [A11]
         * <hr>
         */

        public LookupCase in(Class<?> c2) {
            Class<?> c1 = lookupClass();
            Module m1 = c1.getModule();
            Module m2 = c2.getModule();
            Module m0 = prevLookupClass() != null ? prevLookupClass.getModule() : c1.getModule();
            int modes1 = lookupModes();
            int changed = 0;
            // for the purposes of access control then treat classes in different unnamed
            // modules as being in the same module.
            boolean sameModule = (m1 == m2) ||
                                 (!m1.isNamed() && !m2.isNamed());
            boolean samePackage = (c1.getClassLoader() == c2.getClassLoader() &&
                                   c1.getPackageName().equals(c2.getPackageName()));
            boolean sameTopLevel = (topLevelClass(c1) == topLevelClass(c2));
            boolean sameClass = (c1 == c2);
            assert(samePackage  || !sameTopLevel);
            assert(sameTopLevel || !sameClass);
            boolean accessible = sameClass;

            if ((modes1 & PACKAGE) != 0)  accessible |= samePackage;
            if ((modes1 & PUBLIC ) != 0)  {
                if (isModuleAccessible(c2))
                    accessible |= (c2.getModifiers() & PUBLIC) != 0;
                else
                    accessible = false;
            }
            if ((modes1 & UNCONDITIONAL) != 0) {
                if (m2.isExported(c2.getPackageName()))
                    accessible |= (c2.getModifiers() & PUBLIC) != 0;
                else
                    accessible = false;
            }
            if (!accessible) {
                // no access to c2; lose all access.
                changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED|UNCONDITIONAL);  // [A7]
            }
            if (!sameClass) {
                changed |= ORIGINAL;  // [A2]
            }
            if (m2 != m1 && m0 != m1) {
                // hop to a third module; lose all access
                changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED);  // [A8]
            }
            if (!sameModule) {
                changed |= MODULE;  // [A3]
            }
            if (!samePackage) {
                // Different package; loose PACKAGE and lower access.
                changed |= (PACKAGE|PRIVATE|PROTECTED);  // [A4]
            }
            if (!sameTopLevel) {
                // Different top-level class.  Lose PRIVATE and PROTECTED access.
                changed |= (PRIVATE|PROTECTED);  // [A5]
            }
            if (sameClass) {
                assert(changed == 0);       // [A11] (no deprivation if same class)
            }

            if (accessible)  assert((changed & PUBLIC) == 0);
            int modes2 = modes1 & ~changed;
            Class<?> plc = (m1 == m2) ? prevLookupClass() : c1; // [A9] [A10]
            if ((modes1 & UNCONDITIONAL) != 0) plc = null;      // [A8]
            LookupCase l2 = new LookupCase(c2, plc, modes2);
            assert(l2.lookupClass() == c2);         // [A1]
            assert((modes1 | modes2) == modes1);    // [A1-a] (no elevation of access)
            assert(l2.prevLookupClass() == null || (modes2 & MODULE) == 0);
            return l2;
        }

        LookupCase dropLookupMode(int modeToDrop) {
            int oldModes = lookupModes();
            int newModes = oldModes & ~(modeToDrop | PROTECTED | ORIGINAL);
            switch (modeToDrop) {
                case PUBLIC: newModes &= ~(MODULE|PACKAGE|PROTECTED|PRIVATE); break;
                case MODULE: newModes &= ~(PACKAGE|PRIVATE); break;
                case PACKAGE: newModes &= ~(PRIVATE); break;
                case PROTECTED:
                case PRIVATE:
                case ORIGINAL:
                case UNCONDITIONAL: break;
                defaultthrow new IllegalArgumentException(modeToDrop + " is not a valid mode to drop");
            }
            if (newModes == oldModes) return this;  // return self if no change
            LookupCase l2 = new LookupCase(lookupClass(), prevLookupClass(), newModes);
            assert((oldModes | newModes) == oldModes);    // [A2] (no elevation of access)
            assert(l2.prevLookupClass() == null || (newModes & MODULE) == 0);
            return l2;
        }

        boolean isModuleAccessible(Class<?> c) {
            Module m1 = lookupClass().getModule();
            Module m2 = c.getModule();
            Module m0 = prevLookupClass() != null ? prevLookupClass.getModule() : m1;
            String pn = c.getPackageName();
            boolean accessible = m1.canRead(m2) && m2.isExported(pn, m1);
            if (m1 != m0) {
                accessible = accessible && m0.canRead(m2) && m2.isExported(pn, m0);
            }
            return accessible;
        }

        @Override
        public String toString() {
            String s = lookupClass().getSimpleName();
            String lstr = lookupString();
            int sl = lstr.indexOf('/');
            if (sl >= 0)  s += lstr.substring(sl);
            ClassLoader cld = lookupClass().getClassLoader();
            if (cld != THIS_LOADER)  s += "/loader#"+numberOf(cld);
            return s;
        }

        /** Predict the success or failure of accessing this method. */
        public boolean willAccess(Method m) {
            Class<?> c1 = lookupClass();
            Class<?> c2 = m.getDeclaringClass();
            Module m1 = c1.getModule();
            Module m2 = c2.getModule();
            Module m0 = prevLookupClass != null ? prevLookupClass.getModule() : m1;
            // unconditional has access to all public types/members of types that is in a package
            // are unconditionally exported
            if ((lookupModes & UNCONDITIONAL) != 0) {
                return m2.isExported(c2.getPackageName())
                       && Modifier.isPublic(c2.getModifiers())
                       && Modifier.isPublic(m.getModifiers());
            }

            // c1 and c2 are in different module
            if (m1 != m2 || m0 != m2) {
                return (lookupModes & PUBLIC) != 0
                       && isModuleAccessible(c2)
                       && Modifier.isPublic(c2.getModifiers())
                       && Modifier.isPublic(m.getModifiers());
            }

            assert(m1 == m2 && prevLookupClass == null);

            if (!willAccessClass(c2, false))
                return false;

            LookupCase lc = this.in(c2);
            int modes1 = lc.lookupModes();
            int modes2 = fixMods(m.getModifiers());
            // allow private lookup on nestmates. Otherwise, privacy is strictly enforced
            if (c1 != c2 && ((modes2 & PRIVATE) == 0 || !c1.isNestmateOf(c2))) {
                modes1 &= ~PRIVATE;
            }
            // protected access is sometimes allowed
            if ((modes2 & PROTECTED) != 0) {
                int prev = modes2;
                modes2 |= PACKAGE;  // it acts like a package method also
                if ((lookupModes() & PROTECTED) != 0 &&
                    c2.isAssignableFrom(c1))
                    modes2 |= PUBLIC;  // from a subclass, it acts like a public method also
            }
            if (verbosity >= 2)
                System.out.format("%s willAccess %s modes1=0x%h modes2=0x%h => %s%n", lookupString(), lc.lookupString(), modes1, modes2, (modes2 & modes1) != 0);
            return (modes2 & modes1) != 0;
        }

        /** Predict the success or failure of accessing this class. */
        public boolean willAccessClass(Class<?> c2, boolean load) {
            Class<?> c1 = lookupClass();
            if (load && c2.getClassLoader() != null) {
                if (c1.getClassLoader() == null) {
                    // not visible
                    return false;
                }
            }

            Module m1 = c1.getModule();
            Module m2 = c2.getModule();
            Module m0 = prevLookupClass != null ? prevLookupClass.getModule() : m1;
            // unconditional has access to all public types that is in an unconditionally exported package
            if ((lookupModes & UNCONDITIONAL) != 0) {
                return m2.isExported(c2.getPackageName()) && Modifier.isPublic(c2.getModifiers());
            }
            // c1 and c2 are in different module
            if (m1 != m2 || m0 != m2) {
                return (lookupModes & PUBLIC) != 0
                    && isModuleAccessible(c2)
                    && Modifier.isPublic(c2.getModifiers());
            }

            assert(m1 == m2 && prevLookupClass == null);

            LookupCase lc = this.in(c2);
            int modes1 = lc.lookupModes();
            boolean r = false;
            if (modes1 == 0) {
                r = false;
            } else {
                if (Modifier.isPublic(c2.getModifiers())) {
                    if ((modes1 & MODULE) != 0)
                        r = true;
                    else if ((modes1 & PUBLIC) != 0)
                        r = m1.isExported(c2.getPackageName());
                } else {
                    if ((modes1 & PACKAGE) != 0 && c1.getPackage() == c2.getPackage())
                        r = true;
                }
            }
            if (verbosity >= 2) {
                System.out.println(this+" willAccessClass "+lc+" c1="+c1+" c2="+c2+" => "+r);
            }
            return r;
        }
    }

    private static Class<?> topLevelClass(Class<?> cls) {
        Class<?> c = cls;
        for (Class<?> ec; (ec = c.getEnclosingClass()) != null; )
            c = ec;
        assert(c.getEnclosingClass() == null);
        assert(c == cls || cls.getEnclosingClass() != null);
        return c;
    }

    private final TreeSet<LookupCase> CASES = new TreeSet<>();
    private final TreeMap<LookupCase,TreeSet<LookupCase>> CASE_EDGES = new TreeMap<>();
    private final ArrayList<ClassLoader> LOADERS = new ArrayList<>();
    private final ClassLoader THIS_LOADER = this.getClass().getClassLoader();
    { if (THIS_LOADER != null)  LOADERS.add(THIS_LOADER); }  // #1

    private LookupCase lookupCase(String name) {
        for (LookupCase lc : CASES) {
            if (lc.toString().equals(name))
                return lc;
        }
        throw new AssertionError(name);
    }

    private int numberOf(ClassLoader cl) {
        if (cl == null)  return 0;
        int i = LOADERS.indexOf(cl);
        if (i < 0) {
            i = LOADERS.size();
            LOADERS.add(cl);
        }
        return i+1;
    }

    private void addLookupEdge(LookupCase l1, Class<?> c2, LookupCase l2, int dropAccess) {
        TreeSet<LookupCase> edges = CASE_EDGES.get(l2);
        if (edges == null)  CASE_EDGES.put(l2, edges = new TreeSet<>());
        if (edges.add(l1)) {
            Class<?> c1 = l1.lookupClass();
            assert(l2.lookupClass() == c2); // [A1]
            int m1 = l1.lookupModes();
            int m2 = l2.lookupModes();
            assert((m1 | m2) == m1);        // [A2] (no elevation of access)
            LookupCase expect = dropAccess == 0 ? l1.in(c2) : l1.in(c2).dropLookupMode(dropAccess);
            if (!expect.equals(l2))
                System.out.println("*** expect "+l1+" => "+expect+" but got "+l2);
            assertEquals(l2, expect);
        }
    }

    private void makeCases(Lookup[] originalLookups) {
        // make initial set of lookup test cases
        CASES.clear(); LOADERS.clear(); CASE_EDGES.clear();
        ArrayList<Class<?>> classes = new ArrayList<>();
        for (Lookup l : originalLookups) {
            CASES.add(new LookupCase(l));
            classes.remove(l.lookupClass());  // no dups please
            classes.add(l.lookupClass());
        }
        System.out.println("loaders = "+LOADERS);
        int rounds = 0;
        for (int lastCount = -1; lastCount != CASES.size(); ) {
            lastCount = CASES.size();  // if CASES grow in the loop we go round again
            for (LookupCase lc1 : CASES.toArray(new LookupCase[0])) {
                for (int mode : ACCESS_CASES) {
                    LookupCase lc2 = new LookupCase(lc1.lookup().dropLookupMode(mode));
                    addLookupEdge(lc1, lc1.lookupClass(), lc2, mode);
                    CASES.add(lc2);
                }
                for (Class<?> c2 : classes) {
                    LookupCase lc2 = new LookupCase(lc1.lookup().in(c2));
                    addLookupEdge(lc1, c2, lc2, 0);
                    CASES.add(lc2);
                }
            }
            rounds++;
        }
        System.out.println("filled in "+CASES.size()+" cases from "+originalLookups.length+" original cases in "+rounds+" rounds");
        if (false) {
            System.out.println("CASES: {");
            for (LookupCase lc : CASES) {
                System.out.println(lc);
                Set<LookupCase> edges = CASE_EDGES.get(lc);
                if (edges != null)
                    for (LookupCase prev : edges) {
                        System.out.println("\t"+prev);
                    }
            }
            System.out.println("}");
        }
    }

    @Test public void test() {
        makeCases(lookups());
        if (verbosity > 0) {
            verbosity += 9;
            Method pro_in_self = targetMethod(THIS_CLASS, PROTECTED, methodType(void.class));
            testOneAccess(lookupCase("AccessControlTest/module"),  pro_in_self, "find");
            testOneAccess(lookupCase("Remote_subclass/module"),    pro_in_self, "find");
            testOneAccess(lookupCase("Remote_subclass"),           pro_in_self, "find");
            verbosity -= 9;
        }
        Set<Class<?>> targetClassesDone = new HashSet<>();
        for (LookupCase targetCase : CASES) {
            Class<?> targetClass = targetCase.lookupClass();
            if (!targetClassesDone.add(targetClass))  continue;  // already saw this one
            String targetPlace = placeName(targetClass);
            if (targetPlace == null)  continue;  // Object, String, not a target
            for (int targetAccess : ACCESS_CASES) {
                if (targetAccess == MODULE || targetAccess == UNCONDITIONAL)
                    continue;
                MethodType methodType = methodType(void.class);
                Method method = targetMethod(targetClass, targetAccess, methodType);
                // Try to access target method from various contexts.
                for (LookupCase sourceCase : CASES) {
                    testOneAccess(sourceCase, method, "findClass");
                    testOneAccess(sourceCase, method, "accessClass");
                    testOneAccess(sourceCase, method, "find");
                    testOneAccess(sourceCase, method, "unreflect");
                }
            }
        }
        System.out.println("tested "+testCount+" access scenarios; "+testCountFails+" accesses were denied");
    }

    private int testCount, testCountFails;

    private void testOneAccess(LookupCase sourceCase, Method method, String kind) {
        Class<?> targetClass = method.getDeclaringClass();
        String methodName = method.getName();
        MethodType methodType = methodType(method.getReturnType(), method.getParameterTypes());
        boolean isFindOrAccessClass = "findClass".equals(kind) || "accessClass".equals(kind);
        boolean willAccess = isFindOrAccessClass ?
                sourceCase.willAccessClass(targetClass, "findClass".equals(kind)) : sourceCase.willAccess(method);
        boolean didAccess = false;
        ReflectiveOperationException accessError = null;
        try {
            switch (kind) {
            case "accessClass":
                sourceCase.lookup().accessClass(targetClass);
                break;
            case "findClass":
                sourceCase.lookup().findClass(targetClass.getName());
                break;
            case "find":
                if ((method.getModifiers() & Modifier.STATIC) != 0)
                    sourceCase.lookup().findStatic(targetClass, methodName, methodType);
                else
                    sourceCase.lookup().findVirtual(targetClass, methodName, methodType);
                break;
            case "unreflect":
                sourceCase.lookup().unreflect(method);
                break;
            default:
                throw new AssertionError(kind);
            }
            didAccess = true;
        } catch (ReflectiveOperationException ex) {
            accessError = ex;
        }
        if (willAccess != didAccess) {
            System.out.println(sourceCase+" => "+targetClass.getSimpleName()+(isFindOrAccessClass?"":"."+methodName+methodType));
            System.out.println("fail "+(isFindOrAccessClass?kind:"on "+method)+" ex="+accessError);
            assertEquals(willAccess, didAccess);
        }
        testCount++;
        if (!didAccess)  testCountFails++;
    }

    static Method targetMethod(Class<?> targetClass, int targetAccess, MethodType methodType) {
        String methodName = accessName(targetAccess)+placeName(targetClass);
        if (verbosity >= 2)
            System.out.println(targetClass.getSimpleName()+"."+methodName+methodType);
        try {
            Method method = targetClass.getDeclaredMethod(methodName, methodType.parameterArray());
            assertEquals(method.getReturnType(), methodType.returnType());
            int haveMods = method.getModifiers();
            assert(Modifier.isStatic(haveMods));
            assert(targetAccess == fixMods(haveMods));
            return method;
        } catch (NoSuchMethodException ex) {
            throw new AssertionError(methodName, ex);
        }
    }

    static String placeName(Class<?> cls) {
        // return "self", "sibling", "nestmate", etc.
        if (cls == AccessControlTest.class)  return "self";
        String cln = cls.getSimpleName();
        int under = cln.lastIndexOf('_');
        if (under < 0)  return null;
        return cln.substring(under+1);
    }
    static String accessName(int acc) {
        switch (acc) {
        case PUBLIC:     return "pub_in_";
        case PROTECTED:  return "pro_in_";
        case PACKAGE:    return "pkg_in_";
        case PRIVATE:    return "pri_in_";
        }
        assert(false);
        return "?";
    }
    private static final int[] ACCESS_CASES = {
        PUBLICPACKAGEPRIVATEPROTECTED, MODULE, UNCONDITIONAL
    };
    /*
     * Adjust PUBLIC => PUBLIC|MODULE|UNCONDITIONAL
     * Adjust 0 => PACKAGE
     */

    /** Return one of the ACCESS_CASES. */
    static int fixMods(int mods) {
        mods &= (PUBLIC|PRIVATE|PROTECTED);
        switch (mods) {
        case PUBLICcase PRIVATEcase PROTECTEDreturn mods;
        case 0:  return PACKAGE;
        }
        throw new AssertionError(mods);
    }

    static Lookup[] lookups() {
        ArrayList<Lookup> tem = new ArrayList<>();
        Collections.addAll(tem,
                           AccessControlTest.lookup_in_self(),
                           Inner_nestmate.lookup_in_nestmate(),
                           AccessControlTest_sibling.lookup_in_sibling());
        if (true) {
            Collections.addAll(tem,Acquaintance_remote.lookups());
        } else {
            try {
                Class<?> remc = Class.forName("test.java.lang.invoke.AccessControlTest_subpkg.Acquaintance_remote");
                Lookup[] remls = (Lookup[]) remc.getMethod("lookups").invoke(null);
                Collections.addAll(tem, remls);
            } catch (ReflectiveOperationException ex) {
                throw new LinkageError("reflection failed", ex);
            }
        }
        tem.add(publicLookup());
        tem.add(publicLookup().in(String.class));
        tem.add(publicLookup().in(List.class));
        return tem.toArray(new Lookup[0]);
    }

    static Lookup lookup_in_self() {
        return MethodHandles.lookup();
    }
    public static      void pub_in_self() { }
    protected static   void pro_in_self() { }
    static /*package*/ void pkg_in_self() { }
    private static     void pri_in_self() { }

    static class Inner_nestmate {
        static Lookup lookup_in_nestmate() {
            return MethodHandles.lookup();
        }
        public static      void pub_in_nestmate() { }
        protected static   void pro_in_nestmate() { }
        static /*package*/ void pkg_in_nestmate() { }
        private static     void pri_in_nestmate() { }
    }
}
class AccessControlTest_sibling {
    static Lookup lookup_in_sibling() {
        return MethodHandles.lookup();
    }
    public static      void pub_in_sibling() { }
    protected static   void pro_in_sibling() { }
    static /*package*/ void pkg_in_sibling() { }
    private static     void pri_in_sibling() { }
}

// This guy tests access from outside the package:
/*
package test.java.lang.invoke.AccessControlTest_subpkg;
public class Acquaintance_remote {
    public static Lookup[] lookups() { ...
    }
    ...
}
*/


Messung V0.5
C=94 H=90 G=91

¤ Dauer der Verarbeitung: 0.9 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge