Implement java collection without losing information - java

I have a class that contains two attributes :
#lombok.Data
public class BusinessObjectCollection<T> implements Serializable {
protected List<T> elements;
protected Integer totalCount;
public BusinessObjectCollection() {
this.elements = new ArrayList<>();
this.totalCount = 0;
}
}
I want this class to implements the interface java.util.Collection in order to call remove(), addAll(), and some other methods directly on the BusinessObjectCollection objet.
So I modify my class like this :
#lombok.Data
public class BusinessObjectCollection<T> implements Collection<T>, Serializable{
protected List<T> elements;
protected Integer totalCount;
public BusinessObjectCollection() {
this.elements = new ArrayList<>();
this.totalCount = 0;
}
#Override
public boolean addAll(Collection<? extends T> c) {
return elements.addAll(c);
}
#Override
public boolean removeAll(Collection<?> c) {
return elements.removeAll(c);
}
[...]
}
My problem is that if I do this, my object lose some informations. I can't see the "elements" and "totalCount" attributes.
Is it possible to use the Collection interface and keep this attributes ?
If no, is there a good alternative ?

You are viewing a feature in your IDE. In your case probably IntelliJ.
When it encounters a Collection, it will only show the contents of the collection and not the actual implementation. This is very useful most of the time, because you are using Collections that might have very complex structures, such as HashSet. But when developing your own collection, you want to see that actual workings in the debugger.
In IntelliJ this is called 'Alternative view for Collection classes'. The manual explains how to disable this.
In Eclipse this is also available (but seems to be turned off by default). The feature is called Logical Structures. This view can be enabled with a toggle button ('Show Logical Structure') in the Variables View.

Related

How to log List interface method for existing code

I have existing codebase that sometimes uses ArrayList or LinkedList and I need to find a way to log whenever add or remove is called to track what has been either added or removed.
What is the best way to make sure I have logging in place?
So for example.
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(123);
and
LinkedList<Integer> anotherNewList = new LinkedList<Integer>();
anotherNewList.add(333);
Not sure if I can intercept add method to achieve this or create overriding class that implements java.util.List interface then use it instead. Either way I'm looking for a good solution that requires minimum intervention and prefrerrably without using any third party packages...
I would use the so called Decorator Pattern to wrap your lists.
This would be a simple example code just to give you an idea:
private static class LogDecorator<T> implements Collection<T> {
private final Collection<T> delegate;
private LogDecorator(Collection<T> delegate) {this.delegate = delegate;}
#Override
public int size() {
return delegate.size();
}
#Override
public boolean isEmpty() {
return delegate.isEmpty();
}
#Override
public boolean contains(Object o) {
return delegate.contains(o);
}
#Override
public Iterator<T> iterator() {
return delegate.iterator();
}
#Override
public Object[] toArray() {
return delegate.toArray();
}
#Override
public <T1> T1[] toArray(T1[] a) {
return delegate.toArray(a);
}
#Override
public boolean add(T t) {
// ADD YOUR INTERCEPTING CODE HERE
return delegate.add(t);
}
#Override
public boolean remove(Object o) {
return delegate.remove(o);
}
#Override
public boolean containsAll(Collection<?> c) {
return delegate.containsAll(c);
}
#Override
public boolean addAll(Collection<? extends T> c) {
return delegate.addAll(c);
}
#Override
public boolean removeAll(Collection<?> c) {
return delegate.removeAll(c);
}
#Override
public boolean retainAll(Collection<?> c) {
return delegate.retainAll(c);
}
#Override
public void clear() {
delegate.clear();
}
}
There is not really a simple way to get there.
Those classes are part of the "standard libraries"; so you can't change their behavior. You could create your own versions of them; and use class path ordering to get them used; but this really dirty hack.
The only other option: extend those classes; #Override the methods you want to be logged; and make sure all your sources use your own versions of those classes. Or if you prefer composition over inheritance you go for the decorator pattern; as suggested by JDC's answer.
The "third" option is really different - you turn to aspect oriented programming (for example using AspectJ) and use such tools to manipulate things on a bytecode level. But that adds a whole new layer of "complexity" to your product; thus I am not counting it as real option.
EDIT on your answer: it seems that you don't understand the difference between interface and implementation?! An interface simply describes a set of method signatures; but in order to have real code behind those methods, there needs to be an implementing class. You see, when you do
List<X> things = new ArrayList<>();
the real type of things is ArrayList; but you rarely care about that real type; it is good enough to know that you can all those List methods on things. So, when you create some new implementation of the List interface ... that doesn't affect any existing
... = new ArrayList ...
declarations at all. You would have to change all assignments to
List<X> things = new YourNewListImplementation<>();
JDC has given a good way to follow.
I would like bring important precisions.
The decorator pattern allows to create a class which decorates another class by adding or removing dynamically a new responsibility to an instance.
In your case, you want to add responsibility.
Decorator is not an intrusive pattern but the decorator class have to conform to the class that it decorates.
So in your case, having a decorator which derives from the Collection interface is not conform to the decorated object since List has methods that Collection has not.
Your need is decorating List instances, so decorator should derive from the List type.
Besides, the decorator class can do, according its needs, a processing before and or after the operation of the class that it decorates but it is also responsible to call the original operation of the decorated class.
In your case, you want to know if an element was added or in or removed from the List. To achieve it, as the method result has consequences on whether you log or not the information, it is preferable to delegate first the processing to the decorated object and then your decorator can perform its processings.
Sometimes, you don't need to decorate a method, don't do it but don't forget to delegate suitably to the decorated object.
import java.util.Iterator;
import java.util.List;
public class DecoratorList<T> implements List<T> {
private static final Tracer tracer = ....;
private List<T> decorated;
private DecoratorList(List<T> decorated) {
this.decorated=decorated;
}
// no decorated methods
....
#Override
public int size() {
return this.decorated.size();
}
#Override
public boolean isEmpty() {
return this.decorated.isEmpty();
}
#Override
public boolean contains(Object o) {
return this.decorated.contains(o);
}
#Override
public Iterator<T> iterator() {
return this.decorated.iterator();
}
....
// end no decorated methods
// exemple of decorated methods
#Override
public void add(int index, T element) {
tracer.info("element " + element + " added to index " + index);
this.decorated.add(index,element);
}
#Override
public boolean remove(Object o) {
final boolean isRemoved = this.decorated.remove(o);
if (isRemoved){
tracer.info("element " + o + " removed");
}
return isRemoved;
}
}
As explained, a decorator is not intrusive for the decorated objects.
So the idea is not changing your code that works but add the decorating operation just after the list be instantiated.
If don't program by interface when you declare your list variables, that is you declare ArrayList list = new ArrayList() instead of List list = new ArrayList() , of course you should change the declared type to List but it doesn't break the code, on the contrary.
Here is your example code :
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(123);
LinkedList<Integer> anotherNewList = new LinkedList<Integer>();
anotherNewList.add(333);
Now, you could do it :
List<Integer> list = new ArrayList<Integer>();
list = new DecoratorList<Integer>(list); // line added
list.add(123);
List<Integer> anotherNewList = new LinkedList<Integer>();
anotherNewList = new DecoratorList<Integer>(anotherNewList); // line added
anotherNewList.add(333);
To ease the task and make it safer, you could even create a util method to apply the decoration on the list :
private static <T> List<T> decorateList(List<T> list) {
list = new DecoratorList<T>(list);
return list;
}
and call it like that :
List<Integer> list = new ArrayList<Integer>();
list = decorateList(list); // line added
list.add(123);
You can use Aspects - but it will log every add and remove call:
#Aspect
public class ListLoggerAspect {
#Around("execution(* java.util.List.add(..))")
public boolean aroundAdd(ProceedingJoinPoint joinPoint) throws Throwable {
boolean result = (boolean) joinPoint.proceed(joinPoint.getArgs());
// do the logging
return result;
}
}
You'll need to configure the aspect in META-INF/aop.xml :
<aspectj>
<aspects>
<aspect name="com.example.ListLoggerAspect"/>
</aspects>
</aspectj>
An easy way to accomplish this is wrapping your source list in a ObservableList and use that as base list. You can simply add an listener to this list to catch every modification (and log out if you wish)
Example:
List obs = FXCollections.observableList(myOriginalList);
obs.addListener(c -> {
for(Item it : c.getRemoved())
System.out.println(it);
for(Item it : c.getAddedSubList())
System.out.println(it);
});
See the javafx documentation on how to add a good listener
Your List is the source here. You need to keep track of the changes to the source. This is a good and natural example of the Observer pattern. You can create an Observable which is your list. Then create some Observers and register them to the Observable. When the Observable is changed, notify all the registered Observers. Inside the Observer you can log the changes using the input event. You should literally implement some ObservableCollection here. You can use Java Rx to get this work done. Please find the sample code given below.
package com.test;
import java.util.ArrayList;
import java.util.List;
import rx.Observable;
import rx.subjects.PublishSubject;
public class ObservableListDemo {
public static class ObservableList<T> {
protected final List<T> list;
protected final PublishSubject<T> onAdd;
public ObservableList() {
this.list = new ArrayList<T>();
this.onAdd = PublishSubject.create();
}
public void add(T value) {
list.add(value);
onAdd.onNext(value);
}
public Observable<T> getObservable() {
return onAdd;
}
}
public static void main(String[] args) throws InterruptedException {
ObservableList<Integer> observableList = new ObservableList<>();
observableList.getObservable().subscribe(System.out::println);
observableList.add(1);
Thread.sleep(1000);
observableList.add(2);
Thread.sleep(1000);
observableList.add(3);
}
}
Hope this helps. Happy coding !
We need a little more information to find the right solution. But I see a number of options.
You can track changes, using a decorator.
You can copy the collection and calculate the changes
You can use aspects to 'decorate' every List in the JVM
Change the existing codebase (a little bit)
1) works if you know exactly how the list is used, and once it is returned to your new code, you are the only user. So the existing code can't have any methods that add to the original list (because would invoke add/remove on the delegate instead of the decorated collection).
2) This approach is used when multiple classes can modify the list. You need to be able to get a copy of the list, before any modifications begin, and then calculate what happened afterwards. If you have access to Apache Collections library you can use CollectionUtils to calculate the intersection and disjunction.
3) This solution requires some for of weaving (compile or load time) as this will create a proxy for every List, so it can add callback code around the method calls. I would not recommend this option unless you have a good understanding of how aspects work, as this solution has a rather steep learning curve, and if something goes wrong and you need to debug you code, it can be a bit tricky.
4) You say existing codebase, which leads me to believe, that you could actually change the code if you really wanted. If this is at all possible, that is the approach I would choose. If the user of the List needs to be able to track changes, then the best possible solution is that the library returns a ChangeTrackingList (interface defining methods from tracking), which you could build using decoration.
One thing you have to be aware of when decorating, is that List has a removeAll() and a addAll(), these methods may or may not call the add() and remove(), this depends on the list implementation. If you are not aware of how these methods are invoked internally you could end up seeing an object as removed twice (unless you can use a set).

Subclassing HashBasedTable from guava collection

I have a multilevel map requirement and I am using Guava Table . More precisely HashBasedTable.
Since my code needs a lot of custom processing on this dataset I would like to implement a derived class e.g. EventActionRuleTable which holds a map of Event - Action objects against a source.
something like this
HashMap<Source , Map<Event, Action> ruleMap ;
I am replacing the above with a
Table<Source, Event , Action> ruleTable = HashBasedTable.create();
But to hold all my custom code I would like to subclass HashBasedTable and figured its simply not possible.
Thus I choose to go with a delegate i.e.
public EventActionRule extends Table<Source, Event, Action>{
private HashBasedTable<Source, Event, Action> backup = null ;
public HashBasedTable<Source, Event, Action> getBackupTable() {
if (backupTable == null) {
backupTable = HashBasedTable.create() ;
}
return backupTable;
}
#Override
public boolean isEmpty() {
return getBackupTable().isEmpty();
}
/**
All other methods of Table interface overridden to delegate calls to backup instance
*/
....
}
Is this approach correct ? Can you list issues if its not ? Any alternative approach ?
Is HashBasedTable Gwt serialization compatible ? I am asking since the two backup maps used internally in the HashBasedTable are annotated with #GwtTransient annotation.
Ad 1. Your approach is correct, although you can use built-in Guava solution for using delegates - Forwarding Decorators:
For all the various collection interfaces, Guava provides Forwarding abstract classes to simplify using the decorator pattern.
In your case, ForwardingTable is waiting for you:
public static class EventActionRule extends ForwardingTable<Source, Event, Action> {
private Table<Source, Event, Action> delegate = HashBasedTable.create();
#Override
protected Table<Source, Event, Action> delegate() {
return delegate;
}
// just an example: isEmpty (and other methods) is ready to be overriden
#Override
public boolean isEmpty() {
boolean isEmpty = delegate().isEmpty();
System.out.println("Was map empty? " + isEmpty);
return isEmpty;
}
}
Ad. 2. Yes, HashBasedTable is serializable under GWT.

JAVA - forced to cast Objects in their own object to apply methods

I have a class collection<T> extends ArrayList()
the object lesCommandes is a collection of multiple Commandes
I stock 3 objects from the class Commandes in it and when i want to apply methods to one of them this.lesCommandes.get(1).xmlCommande() i need to cast it or it doesn't work ((Commande)this.lesCommandes.get(1)).xmlCommande()
class Collection<T> extends ArrayList{}
this.commande1=new Commande(1,10,"filet 1kg",1,"10-12-2015","10-01-2016","en cours");
this.commande2=new Commande(2,15,"filet 5kg",1,"11-11-2015","10-02-2016","livrée");
this.commande3=new Commande(3,20,"caisse 10kg",2,"12-10-2015","10-03-2016","livrée");
this.lesCommandes.add(0, commande1);
this.lesCommandes.add(1, commande2);
this.lesCommandes.add(2, commande3);
xml=((Commande)this.lesCommandes.get(1)).xmlCommande();
You have to extend ArrayList<Commande>, so the objects stored in it will remain of Commande type
First a few advices on design (if I may).
Don't use inheritance for composition.
extends means is a relationship, which is often abused: you can say a GroupOfOrders is a ListOfOrders and define the following (in this case it really means is implemented in terms of):
public GroupOfOrders extends List<Order> {...}
But, it is generally better to define this relation in terms of composition and use the List<T> for the (hidden) implementation.
Why? - because,
you may want to have a hierarchy of GroupOfOrders and you can only extends once,
when you extends you inherit all the public and protected members from the super class. in your case, these methods are not part of the (functional) domain. You may not really want to allow clients of your class to apply any methods from List<T>.
If you decide to change the implementation and say that a GroupOfOrders is actually better implemented with a Set<T>, meaning you don't authorise the duplicate Order into a GroupOfOrders, you can easily do it if you don't extends 'List. It can be very difficult if you extendsList` and client classes use methods from it all over the code - it can be even worse if there are external clients from whom you don't control the code and usage of your class.
Just for the example, I defined the Order class (commande in english is order - It's just a matter of sharing with people, I don't mean you need to translate the code)
public class Order {
// properties, constructor...
public OrderResult executeOrder() {
// just do it
}
public String asXML() {
// generate the order as an XML string
}
}
public class GroupOfOrders {
private List<Order> orders = new ArrayList<>();
public void addOrder(Order o) {
// do some checking on order
orders.add(order);
}
public GroupedOrderResult executeAllOrders() {
GroupedOrderResult result = new GroupedOrderResult();
for (Commande c : commandes) {
OrderResult res = c.executeOrder();
result.add(c, res);
}
return result;
}
List<Order> getOrders() { return orders; }
}
And maybe, somewhere else in the program, when you need to get each order as an XML string:
GroupOfOrders orders; // initialised with the different orders
for (Order o : orders.getOrders()) {
String xmlOrder = o.asXML();
// do what needs to be done with xmlOrder
}
You will note that there is nowhere a need to cast.
Second, a few comments on the code you provided:
class Collection<T> extends ArrayList{}
This doesn't make sense: an ArrayList already implements Collection interface. May be you mean you have
List<T> lesCommandes = new ArrayList<Commande>();
this.commande1=new Commande(1,10,"filet 1kg",1,"10-12-2015","10-01-2016","en cours");
this.commande2=new Commande(2,15,"filet 5kg",1,"11-11-2015","10-02-2016","livrée");
this.commande3=new Commande(3,20,"caisse 10kg",2,"12-10-2015","10-03-2016","livrée");
this.lesCommandes.add(0, commande1);
this.lesCommandes.add(1, commande2);
this.lesCommandes.add(2, commande3);
Just do
lesCommandes.add(commande1); etc..
The List<T>$add(T) will actually add at the end of the list and manage the size dynamically.
xml=((Commande)this.lesCommandes.get(1)).xmlCommande();
If lesCommandes is defined as I suggest and there is a xmlCommande() method in the Commande class, then just do
xml = lesCommandes.get(1).xmlCommande();

Understanding best use of Java Generics in this example case

Let's say I have a manufacturing scheduling system, which is made up of four parts:
There are factories that can manufacture a certain type of product and know if they are busy:
interface Factory<ProductType> {
void buildProduct(ProductType product);
boolean isBusy();
}
There is a set of different products, which (among other things) know in which factory they are built:
interface Product<ActualProductType extends Product<ActualProductType>> {
Factory<ActualProductType> getFactory();
}
Then there is an ordering system that can generate requests for products to be built:
interface OrderSystem {
Product<?> getNextProduct();
}
Finally, there's a dispatcher that grabs the orders and maintains a work-queue for each factory:
class Dispatcher {
Map<Factory<?>, Queue<Product<?>>> workQueues
= new HashMap<Factory<?>, Queue<Product<?>>>();
public void addNextOrder(OrderSystem orderSystem) {
Product<?> nextProduct = orderSystem.getNextProduct();
workQueues.get(nextProduct.getFactory()).add(nextProduct);
}
public void assignWork() {
for (Factory<?> factory: workQueues.keySet())
if (!factory.isBusy())
factory.buildProduct(workQueues.get(factory).poll());
}
}
Disclaimer: This code is merely an example and has several bugs (check if factory exists as a key in workQueues missing, ...) and is highly non-optimal (could iterate over entryset instead of keyset, ...)
Now the question:
The last line in the Dispatcher (factory.buildProduct(workqueues.get(factory).poll());) throws this compile-error:
The method buildProduct(capture#5-of ?) in the type Factory<capture#5-of ?> is not applicable for the arguments (Product<capture#7-of ?>)
I've been racking my brain over how to fix this in a type-safe way, but my Generics-skills have failed me here...
Changing it to the following, for example, doesn't help either:
public void assignWork() {
for (Factory<?> factory: workQueues.keySet())
if (!factory.isBusy()) {
Product<?> product = workQueues.get(factory).poll();
product.getFactory().buildProduct(product);
}
}
Even though in this case it should be clear that this is ok...
I guess I could add a "buildMe()" function to every Product that calls factory.buildProduct(this), but I have a hard time believing that this should be my most elegant solution.
Any ideas?
EDIT:
A quick example for an implementation of Product and Factory:
class Widget implements Product<Widget> {
public String color;
#Override
public Factory<Widget> getFactory() {
return WidgetFactory.INSTANCE;
}
}
class WidgetFactory implements Factory<Widget> {
static final INSTANCE = new WidgetFactory();
#Override
public void buildProduct(Widget product) {
// Build the widget of the given color (product.color)
}
#Override
public boolean isBusy() {
return false; // It's really quick to make this widget
}
}
Your code is weird.
Your problem is that you are passing A Product<?> to a method which expects a ProductType which is actually T.
Also I have no idea what Product is as you don't mention its definition in the OP.
You need to pass a Product<?> to work. I don't know where you will get it as I can not understand what you are trying to do with your code
Map<Factory<?>, Queue<Product<?>>> workQueues = new HashMap<Factory<?>, Queue<Product<?>>>();
// factory has the type "Factory of ?"
for (Factory<?> factory: workqueues.keySet())
// the queue is of type "Queue of Product of ?"
Queue<Product<?>> q = workqueues.get(factory);
// thus you put a "Product of ?" into a method that expects a "?"
// the compiler can't do anything with that.
factory.buildProduct(q.poll());
}
Got it! Thanks to meriton who answered this version of the question:
How to replace run-time instanceof check with compile-time generics validation
I need to baby-step the compiler through the product.getFactory().buildProduct(product)-part by doing this in a separate generic function. Here are the changes that I needed to make to the code to get it to work (what a mess):
Be more specific about the OrderSystem:
interface OrderSystem {
<ProductType extends Product<ProductType>> ProductType getNextProduct();
}
Define my own, more strongly typed queue to hold the products:
#SuppressWarnings("serial")
class MyQueue<T extends Product<T>> extends LinkedList<T> {};
And finally, changing the Dispatcher to this beast:
class Dispatcher {
Map<Factory<?>, MyQueue<?>> workQueues = new HashMap<Factory<?>, MyQueue<?>>();
#SuppressWarnings("unchecked")
public <ProductType extends Product<ProductType>> void addNextOrder(OrderSystem orderSystem) {
ProductType nextProduct = orderSystem.getNextProduct();
MyQueue<ProductType> myQueue = (MyQueue<ProductType>) workQueues.get(nextProduct.getFactory());
myQueue.add(nextProduct);
}
public void assignWork() {
for (Factory<?> factory: workQueues.keySet())
if (!factory.isBusy())
buildProduct(workQueues.get(factory).poll());
}
public <ProductType extends Product<ProductType>> void buildProduct(ProductType product) {
product.getFactory().buildProduct(product);
}
}
Notice all the generic functions, especially the last one. Also notice, that I can NOT inline this function back into my for loop as I did in the original question.
Also note, that the #SuppressWarnings("unchecked") annotation on the addNextOrder() function is needed for the typecast of the queue, not some Product object. Since I only call "add" on this queue, which, after compilation and type-erasure, stores all elements simply as objects, this should not result in any run-time casting exceptions, ever. (Please do correct me if this is wrong!)

Inheritance or not

I am working on a component which is supposed to:
receive data (collection of items) from some external calculation component. I expect about 100-1K of items on input on each request.
validate data, calculate some attributes if missing
persist data
There are about ten types of items. I use inheritance to model items. I have a base item class with common attributes and calculations and subclasses implementing type specific problems. Similar to following example:
public abstract class BaseItem {
String name;
boolean valid = true;
public void postCalucate() {
//common calculation
valid = valid && (name != null);
}
}
public class ItemA extends BaseItem {
BigDecimal value;
#Override
public void postCalucate() {
//some A specific calculations
super.postCalucate();
}
}
public class ItemA1 extends ItemA {
BigDecimal extraValue;
#Override
public void postCalucate() {
//some A1 subtype specific calculations
valid = isA1ItemValid();
super.postCalucate();
}
}
public class ItemB extends BaseItem {
Integer size;
#Override
public void postCalucate() {
//some B specific calculations
super.postCalucate();
}
}
Is there any better way/pattern to do my task? Any advices?
The pattern you are trying to use is fairly sound. In general, I would probably suggest the use of an interface instead of a BaseItem class, since it might not contain that much common functionality.
In general, most people seem to recommend defining interfaces for your classes to implement. If absolutely you want to share common code in an AbstractClass, I would recommend that class implementing the interface, since this pattern would lend itself to greater extensibility and flexibility in the future.
As such, you would first begin by defining what an Item is for you. For me, it seems that an Item is three things in your use case: one, it must define the postCalculate() method that will be called on all Items. Second, it must provide an isValid() method. And third, it should also provide a getName() method.
public interface Item {
void postCalucate();
boolean isValid();
String getName();
}
Then you would begin implementing your Abstract class. Do this only if it really is necessary to share a codebase between all your items.
public abstract class BaseItem implements Item {
String name;
boolean valid = true;
public void postCalucate() {
//common calculation
valid = valid && (name != null);
}
public boolean isValid() {
return valid;
}
public String getName() {
return name;
}
}
If BaseItem.postCalculate() is something that will need to be done for all items, this is a good way to do it. If you're not entirely sure, it might be a good idea instead to define a method somewhere in a Helper or Tool class that performs this common calculation for items, and is called by the postCalculate() methods:
public class ItemTools {
public static boolean meetsRequirements(Item item) {
return item.isValid && item.getName() != null;
}
}
This, many would argue, gives you an easier time as your requirements on BaseItem may change over time.
Regardless of which route you go there, now you'll just have to define your actual items:
public class ItemA extends BaseItem {
BigDecimal value;
#Override
public void postCalucate() {
//some A specific calculations
super.postCalucate();
}
}
While the general advice is to avoid over-usage of inheritance, this is no case of over-usage. So, go ahead with this approach.
Apart from that: Your code shows problems with encapsulation. You shouldn’t have all these non-private field. As a reminder: no visibility at all is package-visibility (visible in the whole package and to all sub-classes). Make your fields private.
A priori, your proposal seems reasonable.
But to be sure, you have to look at all the events of the life cycle of your objects:
instantiation
use, read
collaboration
persistence
...

Categories

Resources