Introspezione Java

di il
7 risposte

Introspezione Java

Ciao a tutti!
Sono un neo Ingegnere Navale con la morbosa passione per la programmazione e mi faccio i miei software in casa.... Purtroppo il mio campo di studi è costellato da formule statistiche e quindi ogni volta che ne trovo una nuova devo riaprire il codice sorgente, inserirla e ricompilare.....

Ho visto su un forum che però è possibile scrivere dei file *.class che estendono un'interface e che è possibile farli leggere al *.jar e questo le integra al suo interno... è possibile fare ciò?

7 Risposte

  • Re: Introspezione Java

    Spiegati meglio.
    Cosa vuoi ottenere?
  • Re: Introspezione Java

    è possibile scrivere dei file *.class che estendono un'interface e che è possibile farli leggere al *.jar e questo le integra al suo interno
    I file .class vengono generati dal compilatore partendo dai file .java

    L'estensione .class e' come l'estensione .o del C. Non associarla ad una classe Java. Dentro un file .class ci puo' stare di tutto!


    Una classe implementa un'interfacca

    Una classe estende un'altra classe

    Una classe NON estende un'interfaccia NE implementa un'altra classe.

    Questo per utilizzare correttamente la terminologia relativa alla programmazione ad oggetti, e non centra con Java, ma e' valida per qualunque linguaggio che suppporta la OOP.

    Un .jar NON LEGGE .class.

    Java legge .class e .jar.

    Un file .jar non e' altro che una serie di file compressi usando il formato dei file ZIP, con un'estensione diversa da .zip.
    Un .jar contiene uno o piu' file .class, organizzato in una struttura gerarchica (stile file system), ed e' l'equivalente delle DLL.


    In Java i file .class indicare direttamente, oppure infilarli tutti dentro uno zip (il .jar di cui sopra) e usare lo zip al loro posto.

    ATTENZIONE: il file .jar deve avere una struttura che rispetta i package!

    Quindi, riformula la domanda: da buon ingegnere sai benissimo che usare i termini a casaccio implica la defenestrazione immediata da parte del professore che ti fa l'esame .
  • Re: Introspezione Java

    @migliorabile hai ragione chiedo venia, cercherò di essere più preciso! Il problema è che avendo imparato Java in maniera totalmente autonoma e non seguendo una procedura organica la mia terminologia può risultare errata!

    Ripartiamo dall'inizio... supponiamo di avere alcune variabili primitive: A,B,C,D,E si possono costruire molte formule (di regressione statistica) con queste: A+B, B+C, C*A,....

    quindi un'implementazione possibile di queste potrebbe essere una enumerazione con un metodo calculate() che ritorni il risultato.

    FORMULA_A -> calculate(double A,double B,double C,double D,double E){return A+B}
    FORMULA_B -> calculate(double A,double B,double C,double D,double E){return B+C}
    FORMULA_C -> calculate(double A,double B,double C,double D,double E){return C*A}

    questo va benissimo ma è una struttura statica, l'utente non può inserire la sua formula!!

    Per fare in modo che l'utente possa inserire la sua formula servirebbe un Parser (vedi eval() di javascript) che però non è disponibile in java che io sappia -.-

    Quindi il problema è questo: fare in modo che l'utente inserisca le SUE formule in qualche modo! Io avevo pensato (sbagliando) che il file *.jar potesse leggere dei file *.class contenti le formule dell'utente all'interno di una classe che implementa un'interfaccia ovvero:
    
    public class MyRegression implements GeneralRegression{
         public calculate(double A,double B,double C,double D){
                return B*D;
         }
    }
    
    Ma a quanto mi dite questo non è possibile....

    Spero di essere stato più chiaro adesso
  • Re: Introspezione Java

    lory1990 ha scritto:


    Per fare in modo che l'utente possa inserire la sua formula servirebbe un Parser (vedi eval() di javascript) che però non è disponibile in java che io sappia -.-
    Esistono librerie Java esterne che fanno da math expression parser/evaluator.


    lory1990 ha scritto:


    Quindi il problema è questo: fare in modo che l'utente inserisca le SUE formule in qualche modo!
    Dipende da come vuole fornire le SUE formule: come testo in una textbox grafica? Come file di testo? Come script in un qualche linguaggio di scripting (es. Javascript)?
    In tutti questi casi jar/class/reflection non c'entrano nulla!
    Al massimo c'entra quanto detto: un math expression parser. O al limite (scripting in qualche linguaggio dinamico) sfruttando la Scripting API disponibile da Java 6 (da questa versione è anche integrato un engine Javascript nel framework).

    lory1990 ha scritto:


    all'interno di una classe che implementa un'interfaccia ovvero:
    
    public class MyRegression implements GeneralRegression{
         public calculate(double A,double B,double C,double D){
                return B*D;
         }
    }
    
    Ma a quanto mi dite questo non è possibile....
    Certo, questo è perfettamente possibile.
    Se l'utente vuole fornire la SUA classe, quindi un qualcosa di esterno alla tua applicazione, deve fornire le sue classi preferibilmente impacchettate in un jar.

    Qui c'entra la reflection perché si può pensare di realizzare un sistema di gestione delle funzioni "pluggabile", dove la tua applicazione va a cercare dei jar in locazioni "note" e li usa.
    E si può fare in svariati modi ma generalmente non c'è nulla di "gratis", richiede un minimo di sforzo/analisi per stabilire i "contratti" necessari affinché ciò che l'utente fornisce sia riconosciuto dalla applicazione.
  • Re: Introspezione Java

    Ciao
    credo di aver capito cosa intendi con i .jar che possono leggere dei .class: vuoi implementare dei plug in, giusto?
    Un parser e' una buona soluzione, ma da quanto ho capito il plug in sarebbe decisamente meglio, perche' ti permetterebbe piu' liberta' di implementazione. Penso che tu abbia ragione.

    La cosa non e' difficile. Una soluzione veloce potrebbe essere:

    1 - ti definisci un'interfaccia, cosa che peraltro hai gia' fatto:
    
       public interface GeneralRegression
       {
           public double calculate(double a, double b, double c, double d, double e);
       }
    
    Finora hai sempre implementato questa interfaccia all'interno del tuo codice, ora la vuoi implementare anche in jar esterni;

    2 - Compili il tuo codice e crei un .jar. L'interfaccia in questione (i.e. GeneralRegression) potresti decidere di tenerla in questo jar principale oppure di creare un jar a parte, questione di gusti.

    3 - Apri un nuovo progetto, ESTERNO al precedente e ci scrivi la tua nuova funzione:
    
        package com.sottovento.highfly;
    
        public class pluginTest implements GeneralRegression
        {
            @Override
           public double calculate(double a, double b, double c, double d, double e)
           {
               return a + b + c + d + e;
           }
        }
    
    Ovviamente per poterla compilare e' necessario conoscere l'interfaccia GeneralRegression, vale a dire devi mettere nel CLASSPATH il jar compilato precedentemente. Se utilizzi un IDE tipo NetBeans lo puoi fare facilmente aggiungendo la libreria nelle properties del progetto. In Netbeans (ma immagino sia possibile anche negli altri IDE) puoi aggiungere il progetto stesso invece della .jar; questo facilita il debug poiche' passerai da un progetto all'altro senza soluzione di continuita', ed e' un grandissimo vantaggio.

    4 - Sarebbe bello poter configurare i plug-in utilizzando un file di configurazione, giusto? Allora lo creiamo, per esempio nella directory corrente (dove l'applicazione partira'), e decidiamo un formato. Siccome non mi voglio sbattere con XML e quant'altro, uso un file .properties. Dentro potrei scriverci, per esempio:

    plugins.count=1
    plugins1.classname=com.sottovento.highfly.GeneralRegression

    jarfiles.count=1
    jarfile1.filename=C:/MyApplication/pluginTest.jar

    salvo ed esco. Nota che ho separato la configurazione dei jar da quella dei plugin. I motivi principali sono:
    - Un singolo progetto potrebbe implementare piu' plug-in, vale a dire potrebbe avere piu' classi che implementano l'interfaccia che ti interessa;
    - Potresti avere bisogno di librerie esterne (i.e. altri jar), per esempio librerie che hai trovato su internet per fare i calcoli, o librerie contenenti driver per accedere ai dati di un database, ecc.

    Penso sia chiaro come devi fare se vuoi aggiungere altri plug in...

    5 - Sai come fare a caricare un file del genere, giusto?
    Per sicurezza, te lo scrivo:
    
     // ritorna le properties lette dal file
     public Properties loadProperties() throws IOException
     {
        Properties props = new Properties();
        try (FileInputStream fis = new FileInputStream("myConfigurationFile.properties"))
        {
            props.load(fis);
        }
     }
    
    6 - Torniamo al programma principale, visto che siamo pronti per implementare il caricamento. Per prima cosa, occorre modificare il classpath dinamicamente, in modo da aggiungere i .jar che hai configurato.
    Puoi fare una cosa del genere (tralascio il controllo delle eccezioni e tutto il resto, e' solo uno schema):
    
        private URLClassLoader addJars(Properties props) throws MalformedURLException
        {
            int jarCount = Integer.parseInt(props.getProperty("jarfiles.count"));
            URL[] vectURL = new URL[jarCount];
            for (int i = 0; i < jarCount; i++)
            {
                String filename = props.getProperty("jarfile" + (i+1) + ".filename");
                URL u = new File(filename).toURI().toURL();
                vectURL[i] = u;
            }
    
            URLClassLoader loader = new URLClassLoader(vectURL);
            return loader;
        }
    
    Ok, hai il tuo nuovo "classpath".

    7 - Ora puoi caricare i plug in usando questo nuovo classpath dinamico (anche in questo caso non controllo tutte le condizioni di errore, e' solo uno schema):
    
        private GeneralRegression[] loadPlugins(Properties props, URLClassLoader cl) throws LinkageError, ExceptionInInitializerError, ClassNotFoundException
        {
            int pluginCount = Integer.parseInt(props.getProperty("plugins.count")); // Fai qualche controllo, per esempio se hai l'eccezione NumberFormatException, ecc
            GeneralRegression[] vectPlugins = new GeneralRegression[pluginCount];
    
            for (int i = 0; i < pluginCount; i++)
            {
                String className = props.getProperty("plugins" + (i+1) + ".classname"); // Fai qualche controllo sul nome della classe, ecc.
                vectPlugins[i] = (GeneralRegression)Class.forName(className, true, cl).newInstance();       // Dovresti fare il controllo sul tipo, per evitare ClassCastException nel caso qualcuno si dimentichi di implementare l'interfaccia
            }
            return vectPlugins;
        }
    
    Nel tuo codice ti bastera'
    - caricare il file di configurazione
    
    Properties props = loadProperties();
    
    - chiamare il loader:
    
    URLClassLoader cl = addJars(props);
    
    - caricare i plugins:
    
    GeneralRegression[] vectRegressions = loadPlugins(props, cl);
    
    voila'. In vectRegression[] hai tutte le formule che ti interessano, caricabili runtime (quindi senza cambiare il tuo programma tutte le volte) e facilmente usabili, come qualsiasi altra formula che hai all'interno della tua applicazione.
    Per esempio:
    
        ArrayList<GeneralRegression> v = Arrays.asList(vectRegressions);
    
        v.stream().forEach(gr -> risultato = gr.calculate(a, b, c, d, e));
    
    Se le formule necessitano di una propria HMI, il discorso non cambia, puoi sempre aggiungere altri metodi da implementare che ritornano un component, e aggiungerli per esempio ad una JTabbed pane, mostrarli al click su un JTree o qualsiasi altra cosa la tua fantasia ti suggerisce
  • Re: Introspezione Java

    Grazie! davvero grazie! è un'ottima guida sull'argomento! cercherò di implementare il tutto e alpiù continuerò a chiedere!

    Grazie ancora!
  • Re: Introspezione Java

    Tienici aggiornati, sarebbe bello saperlo funzionante...
Devi accedere o registrarti per scrivere nel forum
7 risposte