package com.googlecode.objectify.impl.load; import com.googlecode.objectify.impl.LoadContext; /** * <p>A setter knows how to set a value in an object graph. It may be composed of * a variety of internal setters that know how to set a value deep in an object graph. * The value being set is a <strong>leaf</strong> value from the datastore; that is, * something that it persists directly (basic type or collection of basic types).</p> * * <p>For example, imagine a Setter for a Person entity with property "name.firstName".</p> * <ul> * <li>Transmog will find a property in the Entity called "name.firstName" with value "Bob".</li> * <li>Transmog will look up a Setter for "name.firstName".</li> * <li>Transmog will call setter.set(rootPojo, "Bob")</li> * <li>The EmbeddedClassSetter will create a Person object in rootPojo.name</li> * <li>The EmbeddedClassSetter will delegate to a LeafSetter, passing in the Person</li> * <li>The LeafSetter will set the name field on the Person object. * </ul> * * <p>Setters are a linear chain like a linked list. They are also immutable. You * extend the chain by calling extend(), passing in the new tail; this produces an * entirely new list.</p> */ abstract public class Setter implements Cloneable { /** The next setter to execute in the chain */ Setter next; /** * Called by the Transmog to set a value on an object. Might actually delegate to * some composite setter to actually set a value deep in the structure. */ abstract public void set(Object toPojo, Object value, LoadContext context); /** * @return the next setter in the chain, or null if there is none */ public Setter getNext() { return this.next; } /** * Extends the whole chain, adding a setter to the tail. Since the setters * are immutable, this returns an entirely new list with the tail at the end. */ public Setter extend(Setter tail) { Setter cloned = this.clone(); Setter traverse = cloned; while (traverse.next != null) traverse = traverse.next; traverse.next = tail; return cloned; } /** * Create a copy of this Setter and all child setters in the chain. */ @Override public Setter clone() { try { Setter cloned = (Setter)super.clone(); if (cloned.next != null) cloned.next = cloned.next.clone(); return cloned; } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } } }