Alguém consegue me dar um exemplo de serialização com Gson que funcione?

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.

1 curtida

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:

  1. Enviar as sugestões de mudança, no caso de um update, para um Controller responsável, mantendo assim classes mais coesas
  2. 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.

https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html

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.

1 curtida

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):

Certo. Da pra fazer essa coordenação tanto com a view, quanto com o controller, se o seu model implementar o Delegation pattern. Mas a menos que esteja criando um framework (que não possui controller próprio), é mais fácil jogar para o controller fazer esse meio de campo. Não vejo como você vai conseguir fazer essa coordenação com annotations ou configuração externa. Da pra anotar uma linha específica dentro do método?

A maneira mais simples de fazer isso, no Cocoa por exemplo, é realmente com Delegation. Você pode colocar um property observer (em Swift por exemplo naqueles var x: Int {didSet {...}}) e notificar o Delegate quando acontece um update. Outra forma é usar KVO. Dá também pra usar notificações globais com algo como o NSNotificationCenter.

Outra forma é utilizar frameworks reativos, como o ReactiveCocoa.

Essa parte é crucial. A gente não tem suporte nativo, esse é o problema! Por isso, cada um implementa como acha melhor. Tu acha legal implementar no controller, eu no model. Qual tá certo, de acordo com a idealização do MVC? Nenhum! Hahahahaha

Engraçado como uma discussão sobre serialização com GSON tá indo parar em questões existenciais hahahaha A culpa é minha, desculpe

Não vejo controller como fachada, e sim como um mediator. Por isso não me importo se ele tem 800 linhas (child controllers podem te ajudar aqui) enquanto as outras classes do model possuem 80-320. Isso tb não significa que o controller tem regras de negócio.

É um fato que aplicações front-end tem muito mais código envolvido em mediacao do que com regras de negócio. E lugar de código que media é no controller. Agora se está desenvolvendo um framework, o controller não existe, então nesse caso, faz sentido o desenvolvedor do framework declarar um delegate que pode ser implementado na view (ou no controller, mas isso vai ficar a critério do desenvolvedor da aplicação final).

ps: Ja ouvi muitas críticas ao cocoa por causa da linguagem Obj-C. Mas dizem que Cocoa+Swift+storyboards e o estado da arte em desenvolvimento front-end. Se pensar que programadores Android ainda manipulam xml na mão, entao… é, nos programadores iOS estamos muito bem. :slight_smile:

Tudo bem, respeito sua opinião!

Opa, que bacana, uma simples dúvida minha gerou tanta coisa :relaxed:. Vários conceitos novos, pra mim isso é muito bom. Eu acabei de analisar meu código inteiro, e percebi que nenhum dos binds está ligado diretamente com os atributos do User, ou seja, eu posso remover as Properties e fazer um objeto comum, porém eu tinha planos de fazer um bind que carregaria a imagem a partir da url do atributo Picture em uma ImageView, e gostaria de um bind para que quando eu quizesse alterar, bastava alterar a model, e consequentemente a view seria alterada, mas se não é mesmo possível, eu posso criar um objeto normal e arrumar outra maneira de fazer isso.
Eu só estava mesmo seguindo um padrão de usar StringProperty ao invés de String. Como eu estou iniciando no JavaFX, eu fiquei apaixonado pelos binds :sweat_smile:.

1 curtida

Não se trata de fornecer uma interface única (facade) porque uma app Cocoa pode ter vários controllers durante sua execução.

Isso, concordo! Também não utilizo apenas uma facade única, mas várias facades que oferecem serviços relacionados à alguma parte do sistema. Seria um sistema monolítico, com separação de serviços disponíveis interna, algo do gênero.

Quando eu tava mexendo com iOS, eu comecei a tratar ViewController como parte da View, como o Mediator que você falou, para fazer as interações entre componentes e delegar as funcionalidades de negócio à um controller (ou fachada) pertinente.