import com.google.gson.Gson;
//body é array de byte da mensagem
String message = new String(body, “UTF-8”);
Gson gson = new Gson();
Position position = gson.fromJson(message, Position.class);
System.out.println(message);
Eu salvei assim:
String json = null;
Gson gson = new Gson();
json = gson.toJson(currentUser);
System.out.println(json);
File fJson = new File(Methods.MakeProgramFolder().getAbsolutePath()+"/user.json");
if(!fJson.exists()){fJson.createNewFile();}
BufferedWriter buffWrite = new BufferedWriter(new FileWriter(fJson));
buffWrite.append(json);
buffWrite.close();
E estou lendo assim:
File fJson = new File(Methods.MakeProgramFolder().getAbsolutePath()+"/user.json");
if(!fJson.exists()){fJson.createNewFile();}
BufferedReader br = new BufferedReader(new FileReader(fJson));
String line;
String json = "";
while((line = br.readLine()) !=null){
json+=line;
}
String u = new String(json.getBytes(), "UTF-8");
Gson gson = new Gson();
User user = gson.fromJson(u, User.class);
System.out.println(u);
//UserDAO.signInOffline(user);
E estou recebendo esta exceção:
Exception in thread "main" java.lang.RuntimeException: Failed to invoke public javafx.beans.property.StringProperty() with no args
at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:111)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:210)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
at com.google.gson.Gson.fromJson(Gson.java:887)
at com.google.gson.Gson.fromJson(Gson.java:852)
at com.google.gson.Gson.fromJson(Gson.java:801)
at com.google.gson.Gson.fromJson(Gson.java:773)
at com.tkfentreteniment.meusdados.start.Start.main(Start.java:36)
Caused by: java.lang.InstantiationException
at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:108)
... 8 more
Ele está com problema na escrita ou leitura?
O que tem nessa linha?
at com.tkfentreteniment.meusdados.start.Start.main(Start.java:36)
User user = gson.fromJson(u, User.class);
Se for bindings javafx que está falando, talvez você deveria renomear o objeto User para UserView.
Ele está gerando o json?
Leitura e escrita são projetos diferentes? Estão em pastas diferentes?
A leitura e a escrita eu realizo a partir de classes diferentes. O caminho está correto, e o .json fica assim:
{"Name":{"name":"","value":"ThallyssonKlein","valid":false},"Email":{"name":"","value":" thallyssonklein@gmail.com","valid":false},"Gender":{"name":"","value":false,"valid":true},"Picture":{"name":"","value":" https://lh5.googleusercontent.com/-R5JjRw7ocHs/AAAAAAAAAAI/AAAAAAAAIV8/jmrc9URk6fM/photo.jpg","valid":false},"googleId":{"name":"","value":"117892930171106636776","valid":true},"Events":[]}
As classes precisam ser idênticas
Não, a classe que está sendo escrita e lida (User) é a mesma. Mas O PROCESSO de leitura e de escrita eu realizo de classes diferentes.
vc pode me enviar o projeto para ler?
Não dá cara, meu projeto tá todo bagunçado e tem umas coisas que eu nem testei ainda. Mas o que eu posso mandar são as partes que mexem com o arquivo e a classe User. O resto do projeto não tem nada a ver com o arquivo.
Classe User:
package com.tkfentretenimento.meusdados.model;
import java.util.ArrayList;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class User {
private StringProperty Name = new SimpleStringProperty();
private StringProperty Email = new SimpleStringProperty();
private BooleanProperty Gender = new SimpleBooleanProperty();
private StringProperty Picture = new SimpleStringProperty();
private StringProperty googleId = new SimpleStringProperty();
private ArrayList<String> Likes = new ArrayList<String>();
private ArrayList<Event> Events = new ArrayList<Event>();
public User(String googleId2, String n, String em, boolean g, String p, ArrayList<String> l) {
this.Name.set(formatName(n));
this.Email.set(em);
this.Gender.set(g);
this.Picture.set(p);
this.Likes = l;
this.googleId.set(googleId2);;
}
public User(){
}
private String formatName(String n){
n = n.replaceFirst(" ", "");
String r = "";
String[] split = n.split(" ");
for(String str : split){
str = str.substring(0,1).toUpperCase().concat(str.substring(1));
r+=str;
}
return r;
}
public final StringProperty NameProperty() {
return this.Name;
}
public final String getName() {
return this.NameProperty().get();
}
public final void setName(final String Name) {
this.NameProperty().set(Name);
}
public final StringProperty emailProperty() {
return this.Email;
}
public final String getEmail() {
return this.emailProperty().get();
}
public final void setEmail(final String email) {
this.emailProperty().set(email);
}
public final BooleanProperty GenderProperty() {
return this.Gender;
}
public final boolean isGender() {
return this.GenderProperty().get();
}
public final void setGender(final boolean Gender) {
this.GenderProperty().set(Gender);
}
public final StringProperty PictureProperty() {
return this.Picture;
}
public final String getPicture() {
return this.PictureProperty().get();
}
public final void setPicture(final String Picture) {
this.PictureProperty().set(Picture);
}
public ArrayList<String> getLikes() {
return Likes;
}
public void setLikes(ArrayList<String> likes) {
Likes = likes;
}
public ArrayList<Event> getEvents() {
return Events;
}
public void setEvents(ArrayList<Event> events) {
this.Events = events;
}
public final StringProperty googleIdProperty() {
return this.googleId;
}
public final String getGoogleId() {
return this.googleIdProperty().get();
}
public final void setGoogleId(final String googleId) {
this.googleIdProperty().set(googleId);
}
}
Escrevendo o User:
String json = null;
Gson gson = new Gson();
json = gson.toJson(currentUser);
System.out.println(json);
File fJson = new File(Methods.MakeProgramFolder().getAbsolutePath()+"/user.json");
if(!fJson.exists()){fJson.createNewFile();}
BufferedWriter buffWrite = new BufferedWriter(new FileWriter(fJson));
buffWrite.append(json);
buffWrite.close();
Lendo o User:
File fJson = new File(Methods.MakeProgramFolder().getAbsolutePath()+"/user.json");
if(!fJson.exists()){fJson.createNewFile();}
BufferedReader br = new BufferedReader(new FileReader(fJson));
String line;
String json = "";
while((line = br.readLine()) !=null){
json+=line;
}
String u = new String(json.getBytes(), "UTF-8");
Gson gson = new Gson();
User user = gson.fromJson(u, User.class);
System.out.println(u);
//UserDAO.signInOffline(user);
O certo seria seu model não ter dependência nenhuma com frontend (pacote javafx.beans.property).
Mas remover apenas os getters/setters com objetos javafx.beans.property na assinatura já resolve o seu problema.
ps: na verdade foi isso que o lvbarbosa mandou fazer, mas vc fez errado.
Eu removi todos, porém o mesmo erro continua. Tá, sobre o model depender da view, eu uso binds com essas properties, tu conhece alguma outra solução para remover essa dependência? E o arquivo continua do mesmo jeito.
Hm… parece que gson tenta serializar os atributos tb, então só separando mesmo.
Sobre separar e não perder os bindings não sei, talvez alguém com mais experiência em javafx pode te ajudar.
Vou tentar fazer uma estrutura para separar. Pior que o modelo MVC presa que as camadas seja separadas, mas eu nem percebi e juntei tudo. Se funcionar depois da separação eu aviso.
Na verdade, o MVC funciona bem parecido com o que você tá fazendo. A ideia é que a View dê sujestões/estímulos ao controller, que vai, de acordo, modificar o modelo caso nenhuma regra de negócio seja infringida. O modelo, por sua vez, quando modificado, notifica a view da mudança e então a view se atualiza para mostrar a mudança ocorrida.
O problema é que é um conceito extremamente teórico e não dá pra implementar de forma simples em linguagens como o Java, que não dão suporte nativo. Seria legal poder simplesmente definir uma configuração ou algum tipo de anotação por padrão e fazer a JVM entender e efetuar essa ligação de forma transparente, mais ou menos como funciona o JPA pra gente (claro, por baixo dos panos, é implementada toda a lógica para fazer introspecção das entidades, mas enfim).
Geralmente se precisa de alguma ferramenta, justamente como os bindings do JavaFX ou algum outro tipo de Observer, que é implementado nativamente em Java, e vem por padrão na forma das classes Observer
e Observable
. Inclusive, se você der uma olhada aqui na documentação da classe Observable, você vai ver que logo no começo tem assim:
This class represents an observable object, or “data” in the model-view paradigm. It can be subclassed to represent an object that the application wants to have observed.
Por esse motivo e alguns outros, começaram a surgir outros “padrões” (não acho que MVC é um padrão de projeto, mas sim uma junção de vários padrões) arquiteturais além do MVC, como MVVM, VIPER e outros parecidos.
Para o teu caso, acho que implementar um modelo arquitetural mais complexo talvez seja bem overkill, vai dar muito trabalho criar um monte de classes para fazer algo simples (não tenho ideia da dimensão do seu projeto, estou chutando). Portanto, acredito que uma solução válida para o teu problema seria o seguinte:
Imagine que você tem a entidade Escola. Você tem uma tela no JavaFX que representa a Escola, podendo ler os dados, edita-los e fazer o que quiser com eles. Você vai definir uma outra classe, que pode chamar por exemplo de EscolaView (esse nome não foi bom, porque talvez view possa dar a ideia de ser realmente visual na tela. Não consegui pensar em outro nome, mas essa classe não representa nenhuma tela) ou algo assim. As bindings do JavaFX vão na classe EscolaView. Dentro da EscolaView, você vai implementar a lógica para efetuar mudanças/consultas no modelo, e pode fazer isso basicamente de duas formas:
- Enviar as sugestões de mudança, no caso de um update, para um Controller responsável, mantendo assim classes mais coesas
- Implementar a lógica de alteração dentro da própria EscolaView, fazendo com que tudo fique mais acoplado, mas simplificando a implementação e gastando menos tempo
Sempre existiu e sempre vai existir essa Navalha de Ockham. Implementar arquiteturas “melhores” (mais coesas) sempre vai dar mais trabalho (ou até que alguém tenha uma ideia genial e facilite isso pra gente), com a vantagem de sustentabilidade (facilidade de manter o código) e, queira ou não queira, beleza (afinal, programar é uma arte!). Porém, você pode sacrificar essas vantagens em prol de salvar tempo e as vezes deixar tudo mais simples.
Qual é melhor? Ninguém descobriu até hoje. A resposta até agora é depende.
Quem usa o model, no caso o controller, é responsável por atualizar view depois de modificar o model. O model não precisa notificar ninguém.
No caso em questão, não sei o que são javafx bindings pra saber se ele fica no controller ou view, mas com certeza não faz sentido ter dependência com javafx no model.
É o que a literatura diz, não to tirando isso do nada. A gente que tá acostumado a programar “em camadas” e chamar de MVC, como eu disse, “burlando” as regras em prol de facilidades e economia de tempo.
No artigo do Wikipedia sobre MVC tem uma foto que ilustra a idealização do mesmo.[quote=“pfk66, post:29, topic:342745”]
mas com certeza não faz sentido ter dependência com javafx no model.
[/quote]
Concordo contigo em partes. Depende do caso! As vezes o esquema é tão simples que não vale a pena criar um monte de classes intermediárias e ficar implementando lógica de tradução de graça. Sou extremamente perfeccionista e não gosto de implementar os famosos God Controllers, mas sei que é overkill as vezes.
EDIT: @pfk66 entendi agora o que você quis dizer com o model não notificar a view, eu acho. Concordo com você, não é no model que vai a lógica explícita de dizer view.update(this)
ou algo assim. Isso teria que ser feito de forma transparente, como disse, com configurações externas ou anotações, e não no controller como geralmente fazemos.
Qual literatura? Web? Desktop?
O framework MVC que uso, Cocoa, chega a cogitar o model notificar controller, mas na minha experiência isso não é nem necessário porque o model não muda por vontade própria, mas sempre em resposta a alguma atualizacao do controller.
Veja que é citado um exemplo do model estar recebendo dados da rede. Mas nas minhas aplicações, quando eu preciso receber alguma coisa da rede, eu coloco esse código no controller.
Antes de mais nada: não quero me provar melhor do que ninguém, de forma alguma. Estou apenas mostrando minhas opiniões e de onde as tirei! Respeito totalmente a experiência e o conhecimento de todos os devs, e quero continuar aprendendo com as divergências.
Já estudei tanto Cocoa quanto CocoaTouch (inclusive tenho licença de desenvolvedor iOS, vai até julho/agosto desse ano) e vi muitas críticas ao modelo MVC da Apple, que eles pregam a implementação de Controllers gordos e cheios de lógica de negócio, o que não deveria ser o caso. Uma busca rápida no google e você vai encontrar dezenas de artigos criticando o que é pregado pela Apple.
Alguns livros sobre design patterns e arquiteturas de sistemas que me recordo de ter lido e embasam meu pensamento:
Design Patterns: Elements of Reusable Object-Oriented Software - Gamma et al.
Clean Code - A Handbook of Agile Software Craftsmanship - Robert C. Martin
Introdução à Arquitetura de Design de Software - Silveira et al. (esse é dos caras da alura)
Head First - Design Patterns (um dos primeiros que eu li)
Domain-Driven Design - Tackling complexity at the Heart of Software - Eric Evans (meu preferido)
E uma série de outros (a grande maioria digital, baixado ilegalmente por um estudante sem dinheiro). To sempre comprando livros novos e lendo sobre isso, porque é um tema que gosto muito e é bem passível de interpretação.
Então, eu discordo dessa abordagem. Mas quem sou eu pra dizer que você tá errado? Cada um faz do jeito que convém! Não existe melhor forma universal, é isso que eu quero dizer, me perdoe se não fui claro. Eu não utilizaria essa abordagem, porque acho que os famosos controllers nada mais deveriam ser do que fachadas da aplicação (ou Application Facades), contendo o mínimo de lógica de negócios, sempre delegando as chamadas para a camáda de domínio e de infraestrutura.
Uma foto da minha mini biblioteca física (que quero muito manter sempre crescendo hehehe):