My JSF Books/Videos My JSF Tutorials OmniFaces/JSF PPTs
JSF 2.3 Tutorial
JSF Caching Tutorial
JSF Navigation Tutorial
JSF Scopes Tutorial
JSF Page Author Beginner's Guide
OmniFaces 2.3 Tutorial Examples
OmniFaces 2.2 Tutorial Examples
JSF Events Tutorial
OmniFaces Callbacks Usages
JSF State Tutorial
JSF and Design Patterns
JSF 2.3 New Features (2.3-m04)
Introduction to OmniFaces
25+ Reasons to use OmniFaces in JSF
OmniFaces Validators
OmniFaces Converters
JSF Design Patterns
Mastering OmniFaces
Reusable and less-verbose JSF code

My JSF Resources ...

Java EE Guardian
Member of JCG Program
Member MVB DZone
Blog curated on ZEEF
OmniFaces is an utility library for JSF, including PrimeFaces, RichFaces, ICEfaces ...

[OmniFaces Utilities] - Find the right JSF OmniFaces 2 utilities methods/functions

Search on blog

Petition by Java EE Guardians

Twitter

marți, 7 aprilie 2015

Copy Objects via OmniFaces Copier API

Starting with version 2.0, OmniFaces provides in the org.omnifaces.util.copier package a set of utilities dedicated for copying objects. In OmniFaces, you can see it at work in <o:validateBean> source code, but you can used it in your projects whenever you need to copy objects (e.g. copy Java beans).
The centerpiece is represented by the Copier interface, which declare a single method named, copy(). This interface acts as a simple contract for keeping everything unitary, and it should be implemented by classes that know how to copy an object:

package org.omnifaces.util.copier;

public interface Copier {
  Object copy(Object object);    
}

This interface is implemented by four classes; each of them defines a copy strategy that is capable to return a copy of an object that satisfies certain requirements. In addition, OmniFaces provides a fifth class (strategy) that represents a straightforward invocation of these four strategies (invoke them in a preset order until one succeeds).
CloneCopier
Copier that copies an object using the Cloneable facility.

public class CloneCopier implements Copier {

  private static final String ERROR_CANT_CLONE =
       "Can not clone object of type %s since it doesn't implement Cloneable";

  @Override
  public Object copy(Object object) {

    if (!(object instanceof Cloneable)) {
        throw new IllegalStateException(format(ERROR_CANT_CLONE, object.getClass()));
    }

    try {
        Method cloneMethod = getMethod(object, "clone");
        if (!cloneMethod.isAccessible()) {
            cloneMethod.setAccessible(true);
        }
        return cloneMethod.invoke(object);
    } catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
      throw new IllegalStateException(e);
    }
  }

  private Method getMethod(Object object, String name) {
    for (Class<?> c = object.getClass(); c != null; c = c.getSuperclass()) {
         for (Method method : c.getDeclaredMethods()) {
              if (method.getName().equals(name)) {
                  return method;
              }
         }
    }

    return null;
  }
}

The source code of CloneCopier reveals that the object that can be copied via this Copier must implement Cloneable interface, and provide a clone() method. If these two mandatory conditions are met, then CloneCopier uses the Java Reflection API to invoke the corresponding clone() method.

Usage - let's suppose the below simple bean that is Cloneable:

public class PlayerCloneable implements Cloneable {

  private String name;
  private String surname;
  private int rank;

  public PlayerCloneable(){       
  }
   
  // This method calls Object's clone().
  PlayerCloneable getClone() throws CloneNotSupportedException {
    // call clone in Object.
    return (PlayerCloneable) super.clone();
  }

  // getters and seeters
}

Now, the object to copy is the following instance of PlayerCloneable:

PlayerCloneable player = new PlayerCloneable();
// set object properties

And, a copy of it can be obtained as:

CloneCopier cloneCopier = new CloneCopier();
PlayerCloneable player_clone = (PlayerCloneable) cloneCopier.copy(player);

SerializationCopier
Copier that copies an object by serializing and subsequently de-serializing it again. As per the platform serialization rules, the object and all its non transient dependencies have to implement the Serializable interface.

public class SerializationCopier implements Copier {

  @Override
  public Object copy(Object object) {

    if (!(object instanceof Serializable)) {
          throw new IllegalStateException("Can't copy object of type " + object.getClass() + " since it doesn't implement Serializable");
    }

    try {
         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
         new ObjectOutputStream(outputStream).writeObject(object);

         return new ObjectInputStream(new ByteArrayInputStream(outputStream.toByteArray())).readObject();

    } catch (IOException | ClassNotFoundException e) {
      throw new IllegalStateException(e);
    }
  }
}

The source code of SerializationCopier reveals that the object that can be copied via this Copier must implement Serializable interface. If this mandatory condition is met, then OmniFaces uses ObjectOutputStream#writeObject() to serialize the object to be copied. Further, it read back the object (deserialize) via ObjectInputStream#readObject() method.

Usage - let's suppose the below simple bean that is Serializable:

public class PlayerSerializable implements Serializable {

  private String name;
  private String surname;
  private int rank;   

  public PlayerSerializable(){       
  }

  // getters and setters
}

Now, the object to copy is the following instance of PlayerSerializable:

PlayerSerializable player = new PlayerSerializable();
// set object properties

And, a copy of it can be obtained as:

SerializationCopier serializationCopier = new SerializationCopier();
PlayerSerializable player_serializable = (PlayerSerializable) serializationCopier.copy(player);

CopyCtorCopier
Copier that copies an object using its copy constructor.

public class CopyCtorCopier implements Copier {
      
  @Override
  public Object copy(Object object) {
             
    try {
         Constructor<? extends Object> copyConstructor = object.getClass().getConstructor(object.getClass());
                    
         return copyConstructor.newInstance(object);
                    
        } catch (NoSuchMethodException | SecurityException | 
                 InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
          throw new IllegalStateException(e);
        }
  }
}

The source code of CopyCtorCopier reveals that the object that can be copied via this Copier must provide a constructor that takes an object of the same type as the object that's to be constructed. This constructor then initializes itself using the values of this other instance.

Usage - let's suppose the below simple bean:

public class PlayerCopyCtor {

  private String name;
  private String surname;
  private int rank;

  public PlayerCopyCtor() {
  }

  public PlayerCopyCtor(PlayerCopyCtor playerCopyCtor) {
    this.name = playerCopyCtor.getName();
    this.surname = playerCopyCtor.getSurname();
    this.rank = playerCopyCtor.getRank();
  }

  // getters and setters
}

Now, the object to copy is the following instance of PlayerCopyCtor:

PlayerCopyCtor player = new PlayerCopyCtor();
// set object properties

And, a copy of it can be obtained as:

CopyCtorCopier copyCtorCopier = new CopyCtorCopier();
PlayerCopyCtor player_copyctor = (PlayerCopyCtor) copyCtorCopier.copy(player);

NewInstanceCopier
Copier that doesn't actually copy an object fully, but just returns a new instance of the same type. This Copier will not preserves the object properties!

public class NewInstanceCopier implements Copier {

  @Override
  public Object copy(Object object) {
    try {
         return object.getClass().newInstance();
    } catch (InstantiationException | IllegalAccessException e) {
         throw new IllegalStateException(e);
    }
  }
}

The source code of NewInstanceCopier reveals that the object that can be copied via this Copier must  implement a public default constructor.

Usage - let's suppose the below simple bean:

public class PlayerNewInstance {

  private String name;
  private String surname;
  private int rank;

  public PlayerNewInstance() {
  }   

  // getters and setters
}

Now, the object to copy is the following instance of PlayerNewInstance:

PlayerPartial player = new PlayerPartial();
// set object properties

And, a copy of it can be obtained as:

NewInstanceCopier newInstanceCopier = new NewInstanceCopier();
PlayerNewInstance player_newinstance = (PlayerNewInstance) newInstanceCopier.copy(player);

Complete source code on GitHub.

Note When you don't want to explicitly use one of the above Copiers, you can simply use the MultiStrategyCopier, which will invoke these Copiers, one by one, starting with CloneCopier, continue with SerializationCopier and CopyCtorCopier, and finish with NewInstanceCopier. Whenever one succeeds, the process stops.

MultiStrategyCopier multiStrategyCopier = new MultiStrategyCopier();
MultiStrategyCopier copied = (MultiStrategyCopier) multiStrategyCopier.copy(object_to_copy);

If the OmniFaces Copiers doesn't satisfy your needs, then you can choose to come with your own Copier (for example, if you may need a partial object (only a subset of the original object properties)). 

Niciun comentariu :

Trimiteți un comentariu

JSF BOOKS COLLECTION

Postări populare

OmniFaces/JSF Fans

Follow by Email

Visitors Starting 4 September 2015

Locations of Site Visitors