2009-12-07 2 views
1

Je travaille avec un framework tiers et il s'avère que j'ai besoin d'envelopper certains de ses objets en tant que délégué dans l'une de mes classes.Problème d'accès en Java

class Foo { // 3rd party class. 
    protected void method() {} 
} 

class FooWrapper extends Foo { 
    private Foo mDelegate; 

    public FooWrapper(Foo inDelegate) { 
     mDelegate = inDelegate; 
    } 

    protected void method() { 
     mDelegate.method(); // error can't access protected method() of mDelegate 
    } 
} 

Donc, il y a le problème. J'ai besoin de déléguer cette méthode à l'objet interne mais c'est protégé et donc non accessible.

Des idées sur les moyens de résoudre ce problème particulier? C'est pour Java 1.3.

+1

+1 J'ai frappé ce même problème la semaine dernière et n'a pas pu trouver une solution, à part mettre la classe d'emballage dans le même paquet que l'original. –

Répondre

3

Pourquoi construisez-vous une instance séparée de Foo? FooWrapper est déjà un Foo.

class Foo { 
    protected void method() {} 
} 

class FooWrapper extends Foo { 

    protected void method() { 
     super.method(); 
    } 
} 

Modifier: si vous avez vraiment avoir instance séparée, d'une manière (quoique légèrement laid) est d'utiliser la réflexion:

public class Foo { 

    protected void method() { 
     System.out.println("In Foo.method()"); 
    } 
} 

public class FooWrapper extends Foo { 

    private Foo foo; 

    public FooWrapper(Foo foo) { 
     this.foo = foo; 
    } 

    public void method() { 
     try { 
      Method m = foo.getClass().getDeclaredMethod("method", null); 
      m.setAccessible(true); 
      m.invoke(foo, null); 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Edit2: Sur la base de votre commentaire ci-dessous, ont deux sous-classes de Foo, une qui fournit simplement des versions publiques des méthodes protégées, et une qui remplace toutes les méthodes importantes. Le premier regardera et agir exactement comme un Foo, le second peut faire tout ce que vous devez faire:

public class Foo { 

    protected void method() { 
     System.out.println("In Foo.method()"); 
    } 
} 

public class DelegateFoo extends Foo { 

    public void method() { 
     super.method(); 
    } 
} 

public class FooWrapper extends Foo { 

    private DelegateFoo foo; 

    public FooWrapper(DelegateFoo foo) { 
     this.foo = foo; 
    } 

    public void method() { 
     foo.method(); 
     /* extra logic here */ 
    } 
} 
+1

Parce que j'ai besoin de déléguer ressembler à un Foo mais déléguer à une instance interne d'un autre foo. –

+0

Malheureusement, la plate-forme intégrée sur laquelle je travaille n'a pas les API de réflexion. Soupir. Bonne suggestion cependant. –

+0

Question stupide, mais pourquoi est-ce que vous devez déléguer à une autre instance? En supposant que vous ne remplacerez aucune autre méthode, le comportement sera exactement le même, n'est-ce pas? –

2

Ce que je l'ai fait quand je suis dans une situation comme ça, et ce ne est pas agréable, mais il fonctionne, est de créer un PublicFoo dans le même paquet que Foo (mais dans votre source), de l'étendre et de surcharger la méthode protégée et de la rendre publique.

Maintenant, FooWrapper peut étendre PublicFoo et faire ce que vous voulez. Notez toutefois que si le fichier d'origine est signé et scellé, vous devez supprimer les signatures avant de pouvoir le déployer. (Vous pouvez aller dans le répertoire Manifest dans le pot, et simplement supprimer les certificats)

+0

J'ai pensé à faire cela mais le problème est que mon FooWrapper est passé d'autres sous-classes de Foo que je ne contrôle pas. –

+0

Pour être juste, ceci est similaire à la réponse acceptée. –

-1

Une sous-classe should have access aux méthodes protégées d'une superclasse.

Si vous appelez juste super.method() au lieu de mDelegate.method(), ça ira; vous enveloppez tous les deux la classe parente et en l'instanciant.

+1

Une instance de la classe A n'a pas accès aux méthodes protégées d'une autre instance de la classe A. L'appel de super.method() dans mon FooWrapper annule le but de la délégation. Le FooWrapper doit déléguer ses méthodes à l'instance interne de la même classe. –

0

Eh bien, si elle a l'accès du public à ses propriétés (qu'ils soient ou getters variables publiques), vous pouvez créer un constructeur de copie:

public FooWrapper(Foo inDelegate) { 
    this.property1 = inDelegate.getProperty1(); 
    this.property2 = inDelegate.getProperty2(); 
    // for every property 
} 

Si les propriétés sont des objets ... grand, mieux encore, parce que tout changement que vous ferez apparaîtra quand vous accéderez à l'objet original! (C'est-à-dire, jusqu'à ce que vous remplaciez un de ces objets, que vous devez pour des classes immuables comme la chaîne.)