Domanda

Ho un programma Java che carica i file di classe di terze parti (classi che non ho scritto) e li esegue. Queste classi usano spesso java.util.Random , che per impostazione predefinita genera valori seed iniziali casuali ogni volta che viene istanziata. Per motivi di riproducibilità, voglio dare a queste classi lo stesso seme iniziale ogni volta, cambiandolo solo a mia discrezione.

Ecco alcune delle ovvie soluzioni e perché non funzionano:

  1. Usa una classe casuale diversa nei file di classe di terze parti. Il problema qui è che carico solo i file di classe e non posso modificare l'origine.

  2. Usa un classloader personalizzato per caricare la nostra classe Random invece della versione di JVM. Questo approccio non funzionerà perché Java non consente ai classloader di sovrascrivere le classi nel pacchetto java .

  3. Scambia l'implementazione java.util.Random di rt.jar per conto nostro, o inserendo i file in percorsi attendibili per la JVM. Questi approcci richiedono all'utente dell'applicazione di fare confusione con l'installazione di JVM sul proprio computer e non vanno bene.

  4. Aggiunta di una classe java.util.Random personalizzata al bootclasspath. Mentre questo funzionerebbe tecnicamente, per questa particolare applicazione, non è pratico perché questa applicazione è destinata agli utenti finali per l'esecuzione da un IDE. Voglio rendere la gestione dell'app conveniente per gli utenti, il che significa che costringerli a impostare il loro bootclasspath è una seccatura. Non posso nasconderlo in uno script, perché è progettato per essere eseguito da un IDE come Eclipse (per un facile debug.)

Quindi come posso farlo?

È stato utile?

Soluzione

Valuta la possibilità di modificare le librerie di terze parti per farle usare un visto per le loro istanze Casuali. Sebbene non si disponga del codice sorgente, probabilmente è possibile modificare il bytecode per farlo. Un utile toolkit per farlo è ASM .

Altri suggerimenti

La tua opzione 2 funzionerà effettivamente, con le seguenti indicazioni.

Dovrai (come diceva anjab) cambiare il percorso della classe bootstrap.

Nella riga di comando del programma è necessario aggiungere quanto segue:

java -Xbootclasspath / p: C: \ your \ random_impl.jar YourProgram

Supponendo che tu sia sulla macchina Windown o il percorso per quella materia in qualsiasi sistema operativo.

Questa opzione aggiunge le classi nei file jar prima che rt.jar venga caricato. Quindi il tuo Random verrà caricato prima della classe Rt.jar Random.

L'utilizzo viene visualizzato digitando:

java -X

Visualizza tutte le funzionalità X (tra) di JVM. Potrebbe non essere disponibile  su altre implementazioni di VM come JRockit o altro ma è presente su Sun JVM.

-Xbootclasspath / p: antepone davanti al percorso della classe bootstrap

Ho usato questo approccio in un'applicazione in cui la classe ORB predefinita dovrebbe essere sostituita con altre implementazioni ORB. La classe ORB fa parte di Java Core e non ha mai avuto problemi.

Buona fortuna.

Potresti usare AOP per intercettare le chiamate a Casuale e modificare l'arg su ciò che desideri.

Sam

Anche se non puoi cambiare banalmente il classloader per " java.x " e "sun.x" pacchetti, c'è un modo per calcolare il caricamento della classe (e installare un "dopo che la classe è stata codificata e caricata" listener) di queste classi, in modo da poter impostare qualcosa come il seme dopo aver caricato le classi da questi pacchetti. Suggerimento: usa la riflessione.

Comunque, fintanto che non ho ulteriori informazioni su cosa esattamente vuoi ottenere, è abbastanza difficile aiutarti qui.

P.S .: Tieni presente che " statico {} " - i blocchi potrebbero ostacolarti di nuovo a giocare con i semi.

" Usa un classloader personalizzato per caricare la nostra classe Random invece della versione di JVM. Questo approccio non funzionerà perché Java non consente ai classloader di sovrascrivere le classi nel pacchetto java. & Quot;

che ne dici di cambiare il bootclasspath per usare la tua classe casuale personalizzata?

BR, ~ A

Sì, l'opzione 2 funziona: creato due classi a scopo di test denominato ThirdPartyClass.java e Random.java

creato jar da ThirdPartyClass.class

jar -cvf tpc.jar ThirdPartyClass.class

creato jar da Random.class

jar -cvf rt123.jar Random.class

dopo eseguire con il seguente comando:

java  -Xbootclasspath/p:tcp.jar:rt123.jar -cp . -verbose ThirdPartyClass

L'output sarà: valore seed per ThirdPartyClass- > 1

codice sorgente ThirdPartyClass.java ----- >

import java.util.Random;

public class ThirdPartyClass {
    ThirdPartyClass(long seed ) {
        System.out.println("seed value for ThirdPartyClass-> "+seed);
    }   

    public static void main(String [] args) {
        ThirdPartyClass tpc=new ThirdPartyClass(new Random().nextLong());
    }
}

codice sorgente Random.java ------- >

package java.util;

import java.io.Serializable;

public class Random extends Object implements Serializable
{
    public Random() {
    }

    public Random(long seed) {
    }

    public long nextLong() {
        return 1;
    }
}

Grazie Mahaveer Prasad Mali

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top