C'è un modo per simulare il concetto di "amico" C ++ in Java?


196

Vorrei essere in grado di scrivere una classe Java in un pacchetto che può accedere a metodi non pubblici di una classe in un altro pacchetto senza renderlo una sottoclasse dell'altra classe. È possibile?

Risposte:


466

Ecco un piccolo trucco che uso in JAVA per replicare il meccanismo amico di C ++.

Diciamo che ho una lezione Romeoe un'altra lezione Juliet. Sono in diversi pacchetti (famiglia) per motivi di odio.

Romeovuole cuddle Juliete Julietvuole solo lasciarla Romeo cuddle.

In C ++, Julietdichiarerebbe Romeocome (amante) friendma non ci sono cose simili in Java.

Ecco le lezioni e il trucco:

Prima le signore :

package capulet;

import montague.Romeo;

public class Juliet {

    public static void cuddle(Romeo.Love love) {
        Objects.requireNonNull(love);
        System.out.println("O Romeo, Romeo, wherefore art thou Romeo?");
    }

}

Quindi il metodo Juliet.cuddleè publicma è necessario un Romeo.Loveper chiamarlo. Lo utilizza Romeo.Lovecome "sicurezza della firma" per garantire che solo Romeoquesto metodo possa essere chiamato e controlla che l'amore sia reale, in modo che l'autonomia lanci un NullPointerExceptionse lo è null.

Adesso ragazzi:

package montague;

import capulet.Juliet;

public class Romeo {
    public static final class Love { private Love() {} }
    private static final Love love = new Love();

    public static void cuddleJuliet() {
        Juliet.cuddle(love);
    }
}

La classe Romeo.Loveè pubblica, ma lo è il suo costruttore private. Quindi chiunque può vederlo, ma solo Romeopuò costruirlo. Uso un riferimento statico in modo Romeo.Loveche quello che non viene mai utilizzato sia costruito una sola volta e non influisca sull'ottimizzazione.

Pertanto, Romeopuò cuddle Juliete solo lui può perché solo lui può costruire e accedere a un Romeo.Loveesempio, che è richiesto dalla Julieta cuddlelei (altrimenti lei schiaffo con un NullPointerException).


107
+1 per "schiaffeggiarti con una NullPointerException". Molto impressionante.
Nickolas,

2
@Steazy C'è: cerca le annotazioni NotNull, NonNull e CheckForNull. Consulta la documentazione del tuo IDE per scoprire come utilizzare e applicare tali annotazioni. So che IntelliJ lo incorpora per impostazione predefinita e che eclipse ha bisogno di un plugin (come FindBugs).
Salomon BRYS,

27
Si può fare Romeo's Loveper Juliaeterno modificando il lovecampo per essere final;-).
Matthias,

5
@Matthias Il campo dell'amore è statico ... Modificherò la risposta per renderla definitiva;)
Salomon BRYS

12
Tutte le risposte dovrebbero essere come questa (Y) +1 per l'umorismo e il grande esempio.
Zia Ul Rehman Mughal,

54

I progettisti di Java hanno esplicitamente respinto l'idea di amico in quanto funziona in C ++. Metti i tuoi "amici" nello stesso pacchetto. La sicurezza privata, protetta e in pacchetto è applicata come parte del design della lingua.

James Gosling voleva che Java fosse C ++ senza errori. Credo che abbia ritenuto quell'amico un errore perché viola i principi OOP. I pacchetti forniscono un modo ragionevole per organizzare i componenti senza essere troppo puristi riguardo a OOP.

NR ha sottolineato che è possibile imbrogliare con la riflessione, ma funziona anche se non si utilizza SecurityManager. Se si attiva la sicurezza standard Java, non sarà possibile imbrogliare con la riflessione se non si scrive una politica di sicurezza per consentirla in modo specifico.


11
Non intendo essere un pedante, ma i modificatori di accesso non sono un meccanismo di sicurezza.
Greg D

6
I modificatori di accesso fanno parte del modello di sicurezza java. Mi riferivo specificamente a java.lang.RuntimePermission per reflection: accessDeclaredMembers e accessClassInPackage.
David G,

54
Se Gosling pensava davvero che friendviolasse OOP (in particolare, più dell'accesso ai pacchetti) , non lo capiva davvero (del tutto possibile, molte persone lo fraintendono).
Konrad Rudolph,

8
Talvolta i componenti della classe devono essere separati (ad es. Implementazione e API, oggetto principale e adattatore). La protezione a livello di pacchetto è allo stesso tempo troppo permissiva e troppo restrittiva per farlo correttamente.
dhardy,

2
@GregD Potrebbero essere considerati un meccanismo di sicurezza, nel senso che aiutano a impedire agli sviluppatori di utilizzare un membro della classe in modo errato. Penso che probabilmente sarebbe meglio chiamarli meccanismi di sicurezza .
schiaccia il

45

Il concetto di "amico" è utile in Java, ad esempio, per separare un'API dalla sua implementazione. È comune che le classi di implementazione abbiano bisogno di accedere agli interni della classe API, ma questi non dovrebbero essere esposti ai client API. Ciò può essere ottenuto utilizzando il modello "Accesso amico" come descritto di seguito:

La classe esposta tramite l'API:

package api;

public final class Exposed {
    static {
        // Declare classes in the implementation package as 'friends'
        Accessor.setInstance(new AccessorImpl());
    }

    // Only accessible by 'friend' classes.
    Exposed() {

    }

    // Only accessible by 'friend' classes.
    void sayHello() {
        System.out.println("Hello");
    }

    static final class AccessorImpl extends Accessor {
        protected Exposed createExposed() {
            return new Exposed();
        }

        protected void sayHello(Exposed exposed) {
            exposed.sayHello();
        }
    }
}

La classe che fornisce la funzionalità "amico":

package impl;

public abstract class Accessor {

    private static Accessor instance;

    static Accessor getInstance() {
        Accessor a = instance;
        if (a != null) {
            return a;
        }

        return createInstance();
    }

    private static Accessor createInstance() {
        try {
            Class.forName(Exposed.class.getName(), true, 
                Exposed.class.getClassLoader());
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException(e);
        }

        return instance;
    }

    public static void setInstance(Accessor accessor) {
        if (instance != null) {
            throw new IllegalStateException(
                "Accessor instance already set");
        }

        instance = accessor;
    }

    protected abstract Exposed createExposed();

    protected abstract void sayHello(Exposed exposed);
}

Esempio di accesso da una classe nel pacchetto di implementazione "amico":

package impl;

public final class FriendlyAccessExample {
    public static void main(String[] args) {
        Accessor accessor = Accessor.getInstance();
        Exposed exposed = accessor.createExposed();
        accessor.sayHello(exposed);
    }
}

1
Perché non sapevo cosa significhi "statico" nella classe "Esposta": il blocco statico è un blocco di istruzioni all'interno di una classe Java che verrà eseguito quando una classe viene caricata per la prima volta nella JVM Leggi di più su javatutorialhub. com /…
Guy L

Modello interessante ma richiede che le classi Exposed e Accessor siano pubbliche mentre le classi che implementano un'API (ovvero un set di classi Java che implementano un set di interfacce Java pubbliche) sarebbero meglio "protette da default" e, quindi, inaccessibili al client per separare i tipi dalle loro implementazioni.
Yann-Gaël Guéhéneuc,

8
Sono abbastanza arrugginito sul mio Java, quindi perdona la mia ignoranza. Qual è il vantaggio di questo rispetto alla soluzione "Romeo e Giulietta" pubblicata da Salomon BRYS? Questa implementazione mi spaventerebbe se mi fossi imbattuto in una base di codice (senza la tua spiegazione allegata, ad esempio commenti pesanti). L'approccio di Romeo e Giulietta è molto semplice da capire.
Steazy

1
Questo approccio renderà i problemi visibili solo in fase di esecuzione, mentre l'uso improprio di Romeo e Giulietta li renderebbe visibili in fase di compilazione, durante lo sviluppo.
ymajoros,

1
@ymajoros L'esempio di Romeo e Giulietta non rende visibili gli abusi in fase di compilazione. Si basa su un argomento che viene passato correttamente e viene generata un'eccezione. Quelle sono entrambe azioni di runtime.
Radiodef,

10

Esistono due soluzioni alla tua domanda che non comportano il mantenimento di tutte le classi nello stesso pacchetto.

Il primo è utilizzare il modello di Accessor Friend / Package Friend descritto in (Practical API Design, Tulach 2008).

Il secondo è usare OSGi. C'è un articolo qui che spiega come OSGi realizza questo.

Domande correlate: 1 , 2 e 3 .


7

Per quanto ne so, non è possibile.

Forse, potresti darci qualche dettaglio in più sul tuo design. Domande come queste sono probabilmente il risultato di difetti di progettazione.

Basta considerare

  • Perché quelle classi sono in pacchetti diversi, se sono così strettamente correlati?
  • A ha accesso ai membri privati ​​di B o l'operazione dovrebbe essere spostata in classe B e attivata da A?
  • È davvero una chiamata o la gestione degli eventi è migliore?

3

La risposta di eirikma è semplice ed eccellente. Potrei aggiungere un'altra cosa: invece di avere un metodo accessibile pubblicamente, getFriend () per ottenere un amico che non può essere usato, potresti fare un ulteriore passo e non consentire di ottenere l'amico senza un token: getFriend (Service.FriendToken). Questo FriendToken sarebbe una classe pubblica interna con un costruttore privato, in modo che solo il Servizio possa istanziarne una.


3

Ecco un chiaro esempio di caso d'uso con una Friendclasse riutilizzabile . Il vantaggio di questo meccanismo è la semplicità d'uso. Forse è utile per dare alle classi di unit test più accesso rispetto al resto dell'applicazione.

Per iniziare, ecco un esempio di come utilizzare la Friendclasse.

public class Owner {
    private final String member = "value";

    public String getMember(final Friend friend) {
        // Make sure only a friend is accepted.
        friend.is(Other.class);
        return member;
    }
}

Quindi in un altro pacchetto puoi farlo:

public class Other {
    private final Friend friend = new Friend(this);

    public void test() {
        String s = new Owner().getMember(friend);
        System.out.println(s);
    }
}

La Friendclasse è la seguente.

public final class Friend {
    private final Class as;

    public Friend(final Object is) {
        as = is.getClass();
    }

    public void is(final Class c) {
        if (c == as)
            return;
        throw new ClassCastException(String.format("%s is not an expected friend.", as.getName()));
    }

    public void is(final Class... classes) {
        for (final Class c : classes)
            if (c == as)
                return;
        is((Class)null);
    }
}

Tuttavia, il problema è che può essere abusato in questo modo:

public class Abuser {
    public void doBadThings() {
        Friend badFriend = new Friend(new Other());
        String s = new Owner().getMember(badFriend);
        System.out.println(s);
    }
}

Ora, può essere vero che la Otherclasse non ha costruttori pubblici, rendendo quindi impossibile il Abusercodice sopra . Tuttavia, se la classe ha un costruttore pubblico, allora è probabilmente consigliabile duplicare la classe amico come una classe interna. Prendi questa Other2classe come esempio:

public class Other2 {
    private final Friend friend = new Friend();

    public final class Friend {
        private Friend() {}
        public void check() {}
    }

    public void test() {
        String s = new Owner2().getMember(friend);
        System.out.println(s);
    }
}

E poi la Owner2classe sarebbe così:

public class Owner2 {
    private final String member = "value";

    public String getMember(final Other2.Friend friend) {
        friend.check();
        return member;
    }
}

Nota che la Other2.Friendclasse ha un costruttore privato, rendendolo così un modo molto più sicuro di farlo.


2

La soluzione fornita non era forse la più semplice. Un altro approccio si basa sulla stessa idea del C ++: i membri privati ​​non sono accessibili al di fuori del pacchetto / ambito privato, ad eccezione di una classe specifica che il proprietario rende amico di se stesso.

La classe che necessita dell'accesso di un amico a un membro deve creare una "classe di amicizia" astratta pubblica interna alla quale la classe proprietaria delle proprietà nascoste può esportare l'accesso, restituendo una sottoclasse che implementa i metodi di implementazione dell'accesso. Il metodo "API" della classe amico può essere privato, quindi non è accessibile al di fuori della classe che necessita dell'accesso amico. La sua unica affermazione è una chiamata a un membro protetto astratto implementato dalla classe esportatrice.

Ecco il codice:

Innanzitutto il test che verifica che questo funzioni effettivamente:

package application;

import application.entity.Entity;
import application.service.Service;
import junit.framework.TestCase;

public class EntityFriendTest extends TestCase {
    public void testFriendsAreOkay() {
        Entity entity = new Entity();
        Service service = new Service();
        assertNull("entity should not be processed yet", entity.getPublicData());
        service.processEntity(entity);
        assertNotNull("entity should be processed now", entity.getPublicData());
    }
}

Quindi il servizio che necessita dell'accesso di un amico a un membro privato pacchetto di Entity:

package application.service;

import application.entity.Entity;

public class Service {

    public void processEntity(Entity entity) {
        String value = entity.getFriend().getEntityPackagePrivateData();
        entity.setPublicData(value);
    }

    /**
     * Class that Entity explicitly can expose private aspects to subclasses of.
     * Public, so the class itself is visible in Entity's package.
     */
    public static abstract class EntityFriend {
        /**
         * Access method: private not visible (a.k.a 'friendly') outside enclosing class.
         */
        private String getEntityPackagePrivateData() {
            return getEntityPackagePrivateDataImpl();
        }

        /** contribute access to private member by implementing this */
        protected abstract String getEntityPackagePrivateDataImpl();
    }
}

Infine: la classe Entity che fornisce un facile accesso a un membro privato del pacchetto solo alla classe application.service.Service.

package application.entity;

import application.service.Service;

public class Entity {

    private String publicData;
    private String packagePrivateData = "secret";   

    public String getPublicData() {
        return publicData;
    }

    public void setPublicData(String publicData) {
        this.publicData = publicData;
    }

    String getPackagePrivateData() {
        return packagePrivateData;
    }

    /** provide access to proteced method for Service'e helper class */
    public Service.EntityFriend getFriend() {
        return new Service.EntityFriend() {
            protected String getEntityPackagePrivateDataImpl() {
                return getPackagePrivateData();
            }
        };
    }
}

Va bene, devo ammettere che è un po 'più lungo di "servizio amici :: Servizio;" ma potrebbe essere possibile accorciarlo mantenendo il controllo del tempo di compilazione utilizzando le annotazioni.


Questo non funziona come una normale classe nello stesso pacchetto potrebbe semplicemente ottenere getFriend () e quindi chiamare il metodo protetto bypassando quello privato.
user2219808,

1

In Java è possibile avere una "amicizia relativa al pacchetto". Questo può essere utile per i test unitari. Se non si specifica privato / pubblico / protetto davanti a un metodo, sarà "amico nel pacchetto". Una classe nello stesso pacchetto sarà in grado di accedervi, ma sarà privata al di fuori della classe.

Questa regola non è sempre nota ed è una buona approssimazione di una parola chiave "amico" C ++. Lo trovo un buon sostituto.


1
Questo è vero, ma stavo davvero chiedendo del codice che risiede in diversi pacchetti ...
Matthew Murdoch,

1

Penso che le classi di amici in C ++ siano come il concetto di classe interna in Java. Usando le classi interne puoi effettivamente definire una classe chiusa e una classe chiusa. La classe chiusa ha pieno accesso ai membri pubblici e privati ​​della sua classe allegata. vedi il seguente link: http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html


Ehm, no, non lo sono. È più simile all'amicizia nella vita reale: può, ma non è necessario, reciproco (A essere un amico di B non significa che B è considerato un amico di A), e tu e i tuoi amici potete essere totalmente diversi famiglie e hanno le tue cerchie di amici, forse (ma non necessariamente) sovrapposte. (Non che mi piacerebbe vedere le lezioni con molti amici. Può essere una funzione utile, ma dovrebbe essere usata con cautela.)
Christopher Creutzig

1

Penso che l'approccio dell'uso del modello di accesso agli amici sia troppo complicato. Ho dovuto affrontare lo stesso problema e ho risolto usando il buon vecchio costruttore di copie, noto dal C ++, in Java:

public class ProtectedContainer {
    protected String iwantAccess;

    protected ProtectedContainer() {
        super();
        iwantAccess = "Default string";
    }

    protected ProtectedContainer(ProtectedContainer other) {
        super();
        this.iwantAccess = other.iwantAccess;
    }

    public int calcSquare(int x) {
        iwantAccess = "calculated square";
        return x * x;
    }
}

Nella tua applicazione potresti scrivere il seguente codice:

public class MyApp {

    private static class ProtectedAccessor extends ProtectedContainer {

        protected ProtectedAccessor() {
            super();
        }

        protected PrivateAccessor(ProtectedContainer prot) {
            super(prot);
        }

        public String exposeProtected() {
            return iwantAccess;
        }
    }
}

Il vantaggio di questo metodo è che solo l'applicazione ha accesso ai dati protetti. Non è esattamente una sostituzione della parola chiave friend. Ma penso che sia abbastanza adatto quando scrivi librerie personalizzate e devi accedere ai dati protetti.

Ogni volta che hai a che fare con istanze di ProtectedContainer puoi avvolgerlo attorno al tuo ProtectedAccessor e ottenere l'accesso.

Funziona anche con metodi protetti. Li definisci protetti nella tua API. Più avanti nella tua applicazione scrivi una classe wrapper privata ed esponi il metodo protetto come pubblico. Questo è tutto.


1
Ma ProtectedContainerpuò essere sottoclassato al di fuori del pacchetto!
Raffaello,

0

Se si desidera accedere a metodi protetti, è possibile creare una sottoclasse della classe che si desidera utilizzare che esponga i metodi che si desidera utilizzare come pubblici (o interni allo spazio dei nomi per essere più sicuri) e disporre di un'istanza di quella classe nella propria classe (usalo come proxy).

Per quanto riguarda i metodi privati ​​(penso) sei sfortunato.


0

Sono d'accordo che nella maggior parte dei casi la parola chiave friend non è necessaria.

  • Package-private (aka. Default) è sufficiente nella maggior parte dei casi in cui hai un gruppo di classi fortemente intrecciate
  • Per le classi di debug che desiderano accedere agli interni, di solito rendo il metodo privato e accedo tramite la riflessione. La velocità di solito non è importante qui
  • A volte, si implementa un metodo che è un "hack" o che è soggetto a modifiche. Lo rendo pubblico, ma uso @Deprecated per indicare che non dovresti fare affidamento su questo metodo esistente.

E infine, se è davvero necessario, c'è il modello di accesso degli amici menzionato nelle altre risposte.


0

Non usare una parola chiave o giù di lì.

Potresti "imbrogliare" usando la riflessione ecc., Ma non consiglierei di "imbrogliare".


3
considererei questa una cattiva idea che anche solo suggerire che sia orrendo per me. Ovviamente questo è un cludge nella migliore delle ipotesi e non dovrebbe far parte di alcun progetto.
shsteimer,

0

Un metodo che ho trovato per risolvere questo problema è quello di creare un oggetto accessor, in questo modo:

class Foo {
    private String locked;

    /* Anyone can get locked. */
    public String getLocked() { return locked; }

    /* This is the accessor. Anyone with a reference to this has special access. */
    public class FooAccessor {
        private FooAccessor (){};
        public void setLocked(String locked) { Foo.this.locked = locked; }
    }
    private FooAccessor accessor;

    /** You get an accessor by calling this method. This method can only
     * be called once, so calling is like claiming ownership of the accessor. */
    public FooAccessor getAccessor() {
        if (accessor != null)
            throw new IllegalStateException("Cannot return accessor more than once!");
        return accessor = new FooAccessor();
    }
}

Il primo codice da chiamare getAccessor()"rivendica la proprietà" dell'accessor. Di solito, questo è il codice che crea l'oggetto.

Foo bar = new Foo(); //This object is safe to share.
FooAccessor barAccessor = bar.getAccessor(); //This one is not.

Ciò ha anche un vantaggio rispetto al meccanismo amico di C ++, poiché consente di limitare l'accesso a livello di istanza , anziché a livello di classe . Controllando il riferimento dell'accessorio, si controlla l'accesso all'oggetto. È inoltre possibile creare più accessori e fornire un accesso diverso a ciascuno, il che consente un controllo approfondito su quale codice può accedere a cosa:

class Foo {
    private String secret;
    private String locked;

    /* Anyone can get locked. */
    public String getLocked() { return locked; }

    /* Normal accessor. Can write to locked, but not read secret. */
    public class FooAccessor {
        private FooAccessor (){};
        public void setLocked(String locked) { Foo.this.locked = locked; }
    }
    private FooAccessor accessor;

    public FooAccessor getAccessor() {
        if (accessor != null)
            throw new IllegalStateException("Cannot return accessor more than once!");
        return accessor = new FooAccessor();
    }

    /* Super accessor. Allows access to secret. */
    public class FooSuperAccessor {
        private FooSuperAccessor (){};
        public String getSecret() { return Foo.this.secret; }
    }
    private FooSuperAccessor superAccessor;

    public FooSuperAccessor getAccessor() {
        if (superAccessor != null)
            throw new IllegalStateException("Cannot return accessor more than once!");
        return superAccessor = new FooSuperAccessor();
    }
}

Infine, se desideri che le cose siano un po 'più organizzate, puoi creare un oggetto di riferimento, che tiene tutto insieme. Ciò consente di rivendicare tutti gli accessori con una chiamata di metodo, nonché di tenerli insieme alla loro istanza collegata. Una volta ottenuto il riferimento, è possibile passare gli accessi al codice che ne ha bisogno:

class Foo {
    private String secret;
    private String locked;

    public String getLocked() { return locked; }

    public class FooAccessor {
        private FooAccessor (){};
        public void setLocked(String locked) { Foo.this.locked = locked; }
    }
    public class FooSuperAccessor {
        private FooSuperAccessor (){};
        public String getSecret() { return Foo.this.secret; }
    }
    public class FooReference {
        public final Foo foo;
        public final FooAccessor accessor;
        public final FooSuperAccessor superAccessor;

        private FooReference() {
            this.foo = Foo.this;
            this.accessor = new FooAccessor();
            this.superAccessor = new FooSuperAccessor();
        }
    }

    private FooReference reference;

    /* Beware, anyone with this object has *all* the accessors! */
    public FooReference getReference() {
        if (reference != null)
            throw new IllegalStateException("Cannot return reference more than once!");
        return reference = new FooReference();
    }
}

Dopo molti colpi alla testa (non del genere buono), questa è stata la mia soluzione finale, e mi piace molto. È flessibile, semplice da usare e consente un ottimo controllo sull'accesso alle classi. (L' accesso con solo riferimento è molto utile.) Se si utilizza protetto anziché privato per gli accessori / riferimenti, le sottoclassi di Foo possono persino restituire riferimenti estesi da getReference. Inoltre non richiede alcun riflesso, quindi può essere utilizzato in qualsiasi ambiente.


0

A partire da Java 9, i moduli possono essere utilizzati per rendere questo un problema in molti casi.


0

Preferisco la delega o la composizione o la classe di fabbrica (a seconda del problema che causa questo problema) per evitare di renderla una classe pubblica.

Se si tratta di un problema di "classi di interfaccia / implementazione in pacchetti diversi", utilizzerei una classe di fabbrica pubblica che si troverebbe nello stesso pacchetto del pacchetto impl e impedirebbe l'esposizione della classe impl.

Se si tratta di un problema "Odio rendere pubblica questa classe / metodo solo per fornire questa funzionalità per qualche altra classe in un pacchetto diverso", utilizzerei una classe delegata pubblica nello stesso pacchetto ed esporrei solo quella parte della funzionalità necessario alla classe "outsider".

Alcune di queste decisioni sono guidate dall'architettura di classloading del server di destinazione (bundle OSGi, WAR / EAR, ecc.), Dalle convenzioni sulla distribuzione e sulla denominazione dei pacchetti. Ad esempio, la soluzione sopra proposta, il modello "Friend Accessor" è intelligente per le normali applicazioni Java. Mi chiedo se diventa difficile implementarlo in OSGi a causa della differenza nello stile di caricamento delle classi.


0

Non so se sia utile a nessuno, ma l'ho gestito nel modo seguente:

Ho creato un'interfaccia (AdminRights).

Ogni classe che dovrebbe essere in grado di chiamare dette funzioni dovrebbe implementare AdminRights.

Quindi ho creato una funzione HasAdminRights come segue:

private static final boolean HasAdminRights()
{
    // Gets the current hierarchy of callers
    StackTraceElement[] Callers = new Throwable().getStackTrace();

    // Should never occur with me but if there are less then three StackTraceElements we can't check
    if (Callers.length < 3)
    {
        EE.InvalidCode("Couldn't check for administrator rights");
        return false;

    } else try
    {

        // Now we check the third element as this function is the first and the function wanting to check for the rights the second. We try to use it as a subclass of AdminRights.
        Class.forName(Callers[2].getClassName()).asSubclass(AdminRights.class);

        // If everything worked up to now, it has admin rights!
        return true;

    } catch (java.lang.ClassCastException | ClassNotFoundException e)
    {
        // In the catch, something went wrong and we can deduce that the caller has no admin rights

        EE.InvalidCode(Callers[1].getClassName() + " doesn't have administrator rights");
        return false;
    }
}

-1

Una volta ho visto una soluzione basata su reflection che ha fatto "il controllo degli amici" in fase di esecuzione usando la riflessione e il controllo dello stack di chiamate per vedere se la classe che chiamava il metodo era autorizzata a farlo. Essendo un controllo di runtime, ha l'ovvio inconveniente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.