Simplistic response
You can’t do this in Java.
Impractical response
You could instrumentalize Java classes so as to intercept the accesses and changes made to the objects.
Reasonable response
Implement an object access standard that allows you to reproduce actions performed.
This reminds me of the architectural pattern Event Sourcing, where the operations performed on the data are stored as events, it is then possible to reproduce, undo and browse the history of the system events.
Any change in the data must be made by a class that manages the data and will be represented by an object that contains the event data.
Example
I made a simple implementation based on the question code:
Class Pessoa
I changed it to be immutable because it’s good practice.
public class Pessoa {
private final String nome;
private final int idade;
public Pessoa(String nome, int idade) {
this.nome = nome;
this.idade = idade;
}
public String getNome() { return nome; }
public int getIdade() { return idade; }
@Override
public String toString() { return nome + " / " + idade; }
}
Event interface
interface Event {
void apply(List<Pessoa> lista);
}
Event to add a person
public class AddPessoaEvent implements Event {
private final Pessoa p;
public AddPessoaEvent(Pessoa p) {
this.p = p;
}
@Override
public void apply(List<Pessoa> lista) {
System.out.println("* Adicionando " + p);
lista.add(p);
}
@Override
public String toString() { return "Add " + p.getNome(); }
}
Event to remove a person
public class RemovePessoaEvent implements Event {
private final int index;
public RemovePessoaEvent(int index) {
this.index = index;
}
@Override
public void apply(List<Pessoa> lista) {
System.out.println("* Removendo " + index);
lista.remove(index);
}
@Override
public String toString() { return "Remove " + index; }
}
Event to update a person’s name
public class AtualizaNomePessoaEvent implements Event {
private final int index;
private final String nome;
AtualizaNomePessoaEvent(int index, String nome) {
this.index = index;
this.nome = nome;
}
@Override
public void apply(List<Pessoa> lista) {
System.out.println("* Atualizando " + index + " com nome " + nome);
lista.set(index, new Pessoa(nome, lista.get(index).idade));
}
@Override
public String toString() {
return "Atualiza " + index + " com nome " + nome;
}
}
People List Manager Class
public class PessoasManager {
private final List<Pessoa> listaDePessoas = new ArrayList<>();
private final List<Event> eventos = new ArrayList<>();
public void add(Pessoa p) {
AddPessoaEvent e = new AddPessoaEvent(p);
eventos.add(e);
e.apply(listaDePessoas);
}
public void remove(int index) {
RemovePessoaEvent e = new RemovePessoaEvent(index);
eventos.add(e);
e.apply(listaDePessoas);
}
public void atualizaNome(int index, String nome) {
AtualizaNomePessoaEvent e = new AtualizaNomePessoaEvent(index, nome);
eventos.add(e);
e.apply(listaDePessoas);
}
public List<Pessoa> getListaDePessoas() { return listaDePessoas; }
public List<Event> getEventos() { return eventos; }
public void replay(List<Event> eventos) {
for (Event e : eventos) {
this.eventos.add(e);
e.apply(listaDePessoas);
}
}
}
Using the classes
The main code to perform the operations mentioned in the question would be the following:
PessoasManager pm = new PessoasManager();
pm.add(new Pessoa("Joao", 29));
pm.add(new Pessoa("Ana", 21));
pm.add(new Pessoa("Maria", 25));
pm.atualizaNome(0, "Jao Carlos");
pm.remove(2);
Each person manager method creates the respective event and applies it to the people list. Like each method apply
has a println
, this would print on the console:
Printing lists of people and events:
System.out.println("Pessoas " + pm.getListaDePessoas());
System.out.println("Eventos " + pm.getEventos());
We have the result:
People [Jao Carlos / 29, Ana / 21]
Events [Add Joao, Add Ana, Add Maria, Update 0 with name Jao Carlos, Remove 2]
So, since we have the events, we can apply them again in another list, creating another people manager and using the method replay
:
PessoasManager pm2 = new PessoasManager();
pm2.replay(pm.getEventos());
The second line above will produce the same exact output on the referring console, as the same events will be applied again. And if you print the new list of people it will also be the same as the previous one.
Something interesting about this pattern is that you could replicate events in another data structure by creating another method analogous to apply
. Instead of a list, it could be a connection to the bank, for example.
Disadvantages
The pattern, as applied above, can generate unnecessary events. Imagine a person’s name updated several times.
Therefore, if the history is not important to you, another alternative would be to store the initial list, create a copy of it, apply the changes and in the end generate a diff, that is, a list of differences between initial and final status, so as to perform the minimum number of operations possible when applying them to your other data source.
Another simpler alternative, when the list is small and there are no dependencies, is simply not trying to replicate the process, but replacing the target data with the new data. For example, I worked on a system a few years ago where the user could edit a table. Updating each field and record in the database according to the row and column of the screen was complicated, mainly because the user could arbitrarily include and exclude rows and columns. In this particular situation, we decided that the most viable solution at the time was simply to delete the existing records and recreate them all from the new values.
I’m not sure I understand what information you want to get from the API.
– Maniero
Check the modified ones I have no idea, but the deleted ones, it seems to me that the Arraylist itself reorders the Indice when an item is removed. See the method description
remove()
: Shifts any subsequent Elements to the left (subtracts one from their indices).– user28595
@diegofm did not know the method
remove(int index)
me returns the element removed however the methodremove(Object o)
returns true if the deleted element that was specified exists in the list.– gato
@bigown need to get (a copy of the objects) the objects being removed and changed in the list.
– gato
So suddenly the only possibility I find is to have a class that manipulates the array and the creation/change of the Person objects. Both the array and the objects will be deprived of this class.
– ramaral
It would not be a case of implementing the Observer standard, to monitor changes?
– user28595
@Denercarvalho can post the class
Pessoa
? I may be mistaken in your need, but it doesn’t seem to be the case withObserver
, at least not with what is in the question. You need another object to need to be notified that something has changed in that?– Maniero
Para que futuramente as modificações aplicadas nesses objetos (alteração e exclusão) sejam aplicadas em outro lugar.
Where? You can give details?– Bruno Costa
@mustache I’ll edit here and put the class
Pessoa
– gato
@Brunocost modifications will be applied to an XML file that contains several objects of the Person type.
– gato
@bigown yes need to be notified, to apply the modifications elsewhere.
– gato
@The question got a little wide :) Not that I think it needs to be closed. You can change this class
Pessoa
? Could implement the interfaceClonable
?– Maniero
@bigown if the changes ñ greatly affect the class structure it be changed yes. The interface
Clonable
solucionaria? I even thought of adding the objects that are being deleted and changed in another listlistaPessoasExcluidas
andlistaPessoasAlteradas
but I don’t know if that would be ideal :P– gato
To
Clonable
It is one of the steps, you can do without, but it complicates the use a lot. As it needs to be observable, you will have to put other things anyway, it will be "complicated", there is no way. But that’s it, without knowing what you need any solution is wrong, if you will create a list, if you will notify another class, if you will only return the object, all this requires different solutions. A [mcve] on something so wide and even not clear would help a lot. It is missing right requirements to answer. I do not close because I know you will tidy :)– Maniero
@bigown I could add the whole context, but this would make the question too broad and also very difficult to test the example. I’ll check the interface
Clonable
and see what I can find. It’s okay to close the question, if the community thinks it should be closed I’ll also vote to close it ;)– gato