# Klasse zur Laufzeit ersetzen



## mikachu (20. Aug 2009)

Hi Community,

kann mir jemand eine detaillierte Anweisung geben, wie ich eine Klasse zur Laufzeit mit einer anderen Klasse ersetzen kann?

Ich muss nen Test bauen, der aber in einer bestimmten Klasse andere Funktionalität beinhalten muss, wie die bereits geladene.

FYI: es wird der System-Classloader genutzt.

MfG mikachu


----------



## maki (20. Aug 2009)

> Hi Community,
> 
> kann mir jemand eine detaillierte Anweisung geben, wie ich eine Klasse zur Laufzeit mit einer anderen Klasse ersetzen kann?


Klasse oder Objekt?

Am einfachsten wäre wohl den Setter zu nutzen und eine andere Instanz zu übergeben (Fake, Stub,  Mock, etc. pp.).

Wenn du uns den Code zeigen würdest könnte man wohl konkretere Tipps geben


----------



## faetzminator (20. Aug 2009)

Mit dem System CL funktionierts nicht. Du musst mit einem URLClassLoader die Klassen laden. Zusätzlich musst du schauen, dass die Klassen auf keinen Fall im Classpath (des Sys CL / der VM) sind.


----------



## Shulyn (20. Aug 2009)

maki hat gesagt.:


> Klasse oder Objekt?
> 
> Am einfachsten wäre wohl den Setter zu nutzen und eine andere Instanz zu übergeben (Fake, Stub,  Mock, etc. pp.).



Wie wäre es wenn du dir 1 Klasse schreibst (init class) , in der du alle die du benutzt Initialisierst, und dann setter methoden einbaust. so kannst du einfach diese austauschen. Wenn du immer über die init auf sie zugreifst.

bzw es würde schon reichen wenn nur die auszutauschende class in dieser ist.
Ich tausche so z.B einen ExceptionHandler in der Laufzeit aus um alle Exception die in einer bestimmten zeit auftreten gesondert zu behandeln...


```
Public class init {

private Exceptionhandler handler = null;

public init() {
this.handler = new Exceptionhandler;
}

public void setExceptionHandler (ExceptionHandler handler);
this.handler = handler;

}
```

Ich weiß nicht ob dir das so reichen würde... ist aber der einfachste weg der mit so auf anhieb bei mehr als 30grad einfällt.


----------



## faetzminator (20. Aug 2009)

Hab jetzt ich oder ihr was falsch verstanden? Wegen dem Sys CL Hint denke ich es geht um dynamisches Nachladen von Klassen (bzw. will er (logischerweise) eine Instanz davon haben).


----------



## Ark (20. Aug 2009)

Täte es Vererbung nicht auch?

Ark


----------



## Spacerat (20. Aug 2009)

Kommt drauf an, welche Klassen du wann ändern willst. Sollen es nur Klassen ausserhalb "rt.jar" sein, kannst du einem eigenen ClassLoader den SystemClassLoader als Parent übergeben. Ansonsten musst du von der System-Property "java.system.class.loader" Gebrauch machen und so einen eigenen ClassLoader zum SystemClassLoader machen. In diesem solltest du allerdings eine Instanz des Originalen bereithalten, damit Systempakete (mit allen Sicherheitsmechanismen usw.) überhaupt noch geladen werden können.


----------



## mikachu (21. Aug 2009)

Danke für die vielen Antworten bisher.

Die Klasse, die ich zur Laufzeit ersetzen will, ist eine innere, statische Klasse einer anderen.
Mit Objekten komme ich nicht weiter, weil beim Start der Applikation noch keine bereitstehen. Deswegen dachte ich mir, dass da einfach beim Start eine andere Klasse anstelle der zu ersetzenden Klasse geladen werden könnte...

Die Klasse ist in einem separaten JAR abgelegt und ist IMHO nicht im Systemclasspath.

MfG

Edit 1: Ich habe mich noch nie mit dem ClassLoader-Konzept befasst...
Edit 2: ...sollte aber nicht allzu schwer zu erlernen sein


----------



## mikachu (21. Aug 2009)

Hi,

habs irgendwie gelöst gekriegt ;-).

"Einfach" einen neuen Classloader erstellen, der von URLClassloader ableitet und welcher den System.classloader als parent erhält.

Dann noch loadClass() überschreiben und gut.
So klappts zumindest erstmal.

Danke an alle Beteiligten,
mikachu


----------



## mikachu (24. Aug 2009)

Hallo nochmal,

es kamen andere Aufgaben dazwischen, sodass ich mich erst heute wieder mit dem Thema befassen konnte...

Das geht doch nicht so einfach, wie ich mir es dachte.

Die zu ersetzende Klasse ist eine innere, statische und als final definierte. Eben wegen final keine Ableitung möglich!

Jetzt hab ich das an einem kleinen Test probiert, und bin gescheitert :'(

Hat da ijemand eine lösungsweisende Idee, wie ich da ran gehen kann?

MfG mikachu


----------



## Spacerat (24. Aug 2009)

...bei "loadClass()" waren wir ja schon...
Nun fehlt nur noch das Abfangen des Dateinamens der Klasse. Bei inneren Klassen ist darauf zu achten, dass der Punkt der in Java gewohnten Notation nicht durch einen Slash, sondern durch eine Dollar-Zeichen ("$") getrennt wird.
	
	
	
	





```
package.OuterClass.InnerClass -> package/OuterClass$InnerClass.class
```
Ferner bekommen anonyme Klassen keinen Namen, sondern eine Nummer. Dadurch wird gezieltes Ersetzen ein wenig erschwert.
	
	
	
	





```
package.OuterClass.AnonClass1 -> package/OuterClass$1.class
```
Wurde der Dateiname der zu ersetzenden Klasse erstmal abgefangen, kann die Ersatzdatei von einer anderen Quelle geladen werden und als Byte-Array an "defineClass()" übergeben werden. Innerhalb der Klasse müssen (sollten) der Klassenname, der Paketname und alle von aussen erreichbare Felder und Methoden übereinstimmen.


----------

