Visualizzazione dei risultati da 1 a 10 su 10

Discussione: Aiuto sui generici

  1. #1

    Aiuto sui generici

    ciao!

    c'è qualcosa che mi sfugge sui generici.
    allora, ho una classe con un metodo che legge un file json:
    codice:
    public class ReadJson {
    
        private final Gson gson;
    
        public ReadJson() {
            gson = new Gson();
        }
    
        public <T> List<T> readJson(File file, Class<T> type) throws IOException {
            ArrayList<T> list = new ArrayList<>();
            JsonParser parser = new JsonParser();
            try (BufferedReader bf = new BufferedReader(new FileReader(file))) {
                JsonArray jarray = parser.parse(new JsonReader(bf)).getAsJsonArray();
                for (JsonElement e : jarray) {
                    T element = gson.fromJson(e, type);
                    list.add(element);
                }
            }
            return list;
        }
    }
    poi ho ad esempio una classe Book di questo tipo:
    codice:
    public class Book {
    
        public int id;
        public String title;
        public String author;
        public String editor;
        public double price;
        public String isbn;
        public String note;
    }
    fin qui nessun problema.
    ora devo riempire una TableView in JavaFX.
    questo il controller:
    codice:
    public class ControllerMain<T> {
    
        private ReadJson jsonRead = new ReadJson();
    
        @FXML
    private TableView tblFilm;
    
        @FXML
    private TextField txtSearch;
    
        @FXML
    public void initialize() {
            try {
                List<T> listBooks = jsonRead.readJson(new File(UrlAndPath.JSON_AUTORI), (Class<T>) Book.class);
                System.out.println(listBooks);
                //ObservableList<Book> list = FXCollections.observableArrayList(listBooks);
    } catch (IOException ex) {
                GenericDialog.showDialog(ex.getMessage(), Alert.AlertType.ERROR);
            }
        }
    }
    il System.out mi stampa gli oggetti Book, quindi direi che è tutto a posto.
    il problema è la riga commentata.
    questo il metodo observableArrayList (che fa parte del jdk ovviamente, non è fatto da me):
    codice:
    public static <E> ObservableList<E> observableArrayList(Collection<? extends E> col) {
        ObservableList<E> list = observableArrayList();
        list.addAll(col);
        return list;
    }
    che modifiche dovrei fare secondo voi??

  2. #2
    no ok ho capito dove sbagliavo.
    non so perchè avevo fatto così.

    la correzione:
    codice:
    public class ControllerMain {
    
        private ReadJson jsonRead = new ReadJson();
    
        @FXML
    private TableView tblBooks;
    
        @FXML
    private TextField txtSearch;
    
        @FXML
    public void initialize() {
            try {
                List<Book> listBooks = jsonRead.readJson(new File(UrlAndPath.JSON_AUTORI), Book.class);
                ObservableList<Book> list = FXCollections.observableArrayList(listBooks);
                tblBooks.getColumns().setAll(TableColumns.setcols());
                tblBooks.setItems(list);
    } catch (IOException ex) {
                GenericDialog.showDialog(ex.getMessage(), Alert.AlertType.ERROR);
            }
        }
    }

  3. #3
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    Ok, però ti segnalo che non servirebbe andare ad usare JsonArray, JsonElement, ecc...

    C'è un modo molto più semplice e pulito: sfruttare un "type token".

    codice:
    import java.util.List;
    import com.google.gson.Gson;
    import com.google.gson.reflect.TypeToken;
    
    public class ProvaBooksGson {
        public static void main(String[] args) {
            TypeToken<List<Book>> booksListToken = new TypeToken<List<Book>>() {};
    
            Gson gson = new Gson();
            List<Book> booksList = gson.fromJson("[{\"title\":\"One\"},{\"title\":\"Two\"}]", booksListToken.getType());
    
            System.out.println(booksList);
        }
    }
    
    class Book {
        private String title;
    
        public String getTitle() {
            return title;
        }
    
        public void setTitle(String title) {
            this.title = title;
        }
    
        public String toString() {
            return "Book:" + getTitle();
        }
    }
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  4. #4
    ciao andbin!

    sto provando seguendo il tuo consiglio.
    ho modificato la classe Book:
    codice:
    public class Book {
    
        private String id;
        private String title;
        private String author;
        private String editor;
        private String price;
        private String isbn;
        private String note;        // GETTER E SETTER
    }
    poi ho modificato così:
    codice:
    public class ReadJson {
    
        private final Gson gson;
    
        public ReadJson() {
            gson = new Gson();
        }
    
        public <T> List<T> readJson(File file, Class<T> type) throws IOException {
            TypeToken<List<T>> listTypeToken = new TypeToken<List<T>>(){};
            JsonReader reader = new JsonReader(new FileReader(file));
            List<T> list = gson.fromJson(reader, listTypeToken.getType());
    
            /*ArrayList<T> list = new ArrayList<>();
            JsonParser parser = new JsonParser();
            try (BufferedReader bf = new BufferedReader(new FileReader(file))) {
                JsonArray jarray = parser.parse(new JsonReader(bf)).getAsJsonArray();
                for (JsonElement e : jarray) {
                    T element = gson.fromJson(e, type);
                    list.add(element);
                }
            }*/
    return list;
        }
    }
    però ottengo questo errore:
    codice:
    Caused by: java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.mp.book.Book
    ma ad essere sincero non ho ben capito...

  5. #5
    ciao andbin!

    sto provando seguendo il tuo consiglio.
    ho modificato la classe Book:
    codice:
    public class Book {
    
        private String id;
        private String title;
        private String author;
        private String editor;
        private String price;
        private String isbn;
        private String note;        // GETTER E SETTER
    }
    poi ho modificato così:
    codice:
    public class ReadJson {
    
        private final Gson gson;
    
        public ReadJson() {
            gson = new Gson();
        }
    
        public <T> List<T> readJson(File file, Class<T> type) throws IOException {
            TypeToken<List<T>> listTypeToken = new TypeToken<List<T>>(){};
            JsonReader reader = new JsonReader(new FileReader(file));
            List<T> list = gson.fromJson(reader, listTypeToken.getType());
    
            /*ArrayList<T> list = new ArrayList<>();
            JsonParser parser = new JsonParser();
            try (BufferedReader bf = new BufferedReader(new FileReader(file))) {
                JsonArray jarray = parser.parse(new JsonReader(bf)).getAsJsonArray();
                for (JsonElement e : jarray) {
                    T element = gson.fromJson(e, type);
                    list.add(element);
                }
            }*/
    return list;
        }
    }
    però ottengo questo errore:
    codice:
    Caused by: java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.mp.book.Book
    ma ad essere sincero non ho ben capito...

  6. #6
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    Quote Originariamente inviata da fermat Visualizza il messaggio
    codice:
    public <T> List<T> readJson(File file, Class<T> type) throws IOException {
    No, se vuoi fare un metodo "generico" che presuppone un List "di qualcosa", allora devi passare il TypeToken al metodo.

    codice:
    public <T> List<T> readJson(File file, TypeToken<List<T>> typeToken) throws IOException

    P.S. il JsonReader andrebbe chiuso comunque alla fine.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  7. #7
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    La forma che ho detto prima non è sbagliata ma ovviamente è "fissata" su List. Si può farla ancora più ampia, facendo qualcosa del tipo:

    codice:
    public <T> T readJson(File file, TypeToken<T> typeToken) throws IOException {
        try (JsonReader reader = new JsonReader(new FileReader(file))) {
            T t = gson.fromJson(reader, typeToken.getType());
            return t;
        }
    }

    Così che tu voglia un List<Book> o un Set<Book>, per dire, non ci sono problemi.


    P.S. l'utilizzo di TypeToken di Gson (così come altri simili in altre librerie) prende il nome di "super type token" come è stato definito da Neal Gafter (uno dei progettisti di Java).
    C'è un suo interessante articolo:

    http://gafter.blogspot.it/2006/12/su...pe-tokens.html
    Ultima modifica di andbin; 14-06-2017 a 21:15
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  8. #8
    ok, allora ho modificato usando il metedo più generico:
    codice:
    public class ReadJson {
    
        public <T> T readJson(File file, TypeToken<T> typeToken) throws IOException {
            Gson gson = new Gson();
            try (JsonReader reader = new JsonReader(new FileReader(file))) {
                T t = gson.fromJson(reader, typeToken.getType());
                return t;
            }
        }
    }
    poi lo richiamo così:
    codice:
    TypeToken<List<Book>> bookToken = new TypeToken<List<Book>>() {};
    List<Book> listBooks = jsonRead.readJson(new File(UrlAndPath.JSON_LIBRI), bookToken);
    funzionare funziona, nel senso che il tutto viene valorizzato e visualizzato in maniera corretta.

    quindi, se volessi avere un Set piuttosto che una List:
    codice:
    TypeToken<Set<Book>> bookToken = new TypeToken<Set<Book>>() {};
    Set<Book> listBooks = jsonRead.readJson(new File(UrlAndPath.JSON_LIBRI), bookToken);
    corretto??

    PS: mi leggerò senz'altro l'articolo che mi hai indicato, spero di capirci abbastanza .

  9. #9
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    Quote Originariamente inviata da fermat Visualizza il messaggio
    quindi, se volessi avere un Set piuttosto che una List:
    codice:
    TypeToken<Set<Book>> bookToken = new TypeToken<Set<Book>>() {};
    corretto??
    Sì, basta cambiare la parametrizzazione del TypeToken.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  10. #10
    Quote Originariamente inviata da andbin Visualizza il messaggio
    Sì, basta cambiare la parametrizzazione del TypeToken.
    perfetto, grazie mille come sempre!!!


Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.