5

Quindi adesso ho un server che funziona con ObjectInputStream e ObjectOutputStream.Inviare una classe anonima su socket? (Object..Stream in Java)

Il problema che sto avendo è che ho una classe personalizzata (anonimo) che estende java.lang.Date che sto cercando di inviare al client e quindi compilare.

Così da nessuna parte definisco la classe sul lato client, ma voglio compilare la classe a livello di codice. Ho provato molti metodi diversi, ma ogni volta ottengo un ClassNotFoundException perché la classe non è inizialmente sul lato client.

Class<?> dateClass = (Class<?>) in.readObject(); //This is where the CNF Exception occurs 
Compiler.compileClass(dateClass); 

risposta

7

Il meccanismo di serializzazione Java assume le classi sono noti per la JVM deserializzazione, non invia le definizioni di classe. In particolare, quando serializzi un oggetto Class, non invii il codice byte per quella classe, ma istruisci solo la VM ricevente a cercare l'oggetto Class per una classe con un nome particolare.

Si noti inoltre che un oggetto Class rappresenta una classe definita in JVM, vale a dire che il codice di classe 'bytecode è già stato caricato. Non ha molto senso provare a compilare in classe per generare quel bytecode dopo il caricando la classe.

Quindi, dobbiamo in qualche modo ottenere la definizione della classe sul client. L'approccio più semplice è quello di farlo come qualsiasi altra classe di cui ha bisogno il client (comprimendola nel file jar del client o in qualsiasi modo si utilizzi per installare il programma client). Se ciò non è possibile, è possibile caricare la definizione della classe sulla rete, ad esempio utilizzando un URLClassLoader, oppure è possibile inviare il file di classe attraverso il flusso di serializzazione e, al ricevimento sul client, utilizzare ClassLoader.defineClass per caricare la classe.

PS: questo problema è completamente indipendente dal fatto che la classe sia denominata o meno. Il seguente codice di prova dimostra che gli oggetti di classi anonime possono essere serializzato e deserializzato bene (se il ricevente VM ha la definizione di classe):

ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { 
     Serializable payload = new Serializable() { 
      @Override 
      public String toString() { 
       return "hello from the anonymous class"; 
      } 
     }; 
     oos.writeObject(payload); 
     oos.writeObject(payload.getClass()); 
    } 

    try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { 
     System.out.println(in.readObject()); 
     System.out.println(in.readObject()); 
    } 
+1

Questa è una risposta di gran lunga migliore rispetto al Tosh concisa su nonymising, anche se è una parola divertente. Come "jelly" e "wibble". Quindi se stiamo votando su parole divertenti, allora questa risposta dovrebbe inserire quei voti adesso. – davidfrancis

+0

Questo è ciò che inizialmente pensavo. Invio del file per la classe sulla rete, quindi basta installarlo sulla DIR quando arriva lì. Grazie per la rassicurazione: D – Avogadro

+0

Si dovrebbe essere benissimo mandare la classe anon su un classloader di rete - ad esempio utilizzando rmi il caricamento delle classi è il modo java nativo di fare questo – davidfrancis