001/* 002 * CycleStrategy.java April 2007 003 * 004 * Copyright (C) 2007, Niall Gallagher <niallg@users.sf.net> 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 015 * implied. See the License for the specific language governing 016 * permissions and limitations under the License. 017 */ 018 019package org.simpleframework.xml.strategy; 020 021import static org.simpleframework.xml.strategy.Name.LABEL; 022import static org.simpleframework.xml.strategy.Name.LENGTH; 023import static org.simpleframework.xml.strategy.Name.MARK; 024import static org.simpleframework.xml.strategy.Name.REFER; 025 026import java.util.Map; 027 028import org.simpleframework.xml.stream.NodeMap; 029 030/** 031 * The <code>CycleStrategy</code> represents a strategy that is used 032 * to augment the deserialization and serialization process such that 033 * cycles in an object graph can be supported. This adds additional 034 * attributes to the serialized XML elements so that during the 035 * deserialization process an objects cycles can be created. Without 036 * the use of a strategy such as this, cycles could cause an infinite 037 * loop during the serialization process while traversing the graph. 038 * <pre> 039 * 040 * <root id="1"> 041 * <object id="2"> 042 * <object id="3" name="name">Example</item> 043 * <object reference="2"/> 044 * </object> 045 * </root> 046 * 047 * </pre> 048 * In the above serialized XML there is a circular reference, where 049 * the XML element with id "2" contains a reference to itself. In 050 * most data binding frameworks this will cause an infinite loop, 051 * or in some cases will just fail to represent the references well. 052 * With this strategy you can ensure that cycles in complex object 053 * graphs will be maintained and can be serialized safely. 054 * 055 * @author Niall Gallagher 056 * 057 * @see org.simpleframework.xml.core.Persister 058 * @see org.simpleframework.xml.strategy.Strategy 059 */ 060public class CycleStrategy implements Strategy { 061 062 /** 063 * This is used to maintain session state for writing the graph. 064 */ 065 private final WriteState write; 066 067 /** 068 * This is used to maintain session state for reading the graph. 069 */ 070 private final ReadState read; 071 072 /** 073 * This is used to provide the names of the attributes to use. 074 */ 075 private final Contract contract; 076 077 /** 078 * Constructor for the <code>CycleStrategy</code> object. This is 079 * used to create a strategy with default values. By default the 080 * values used are "id" and "reference". These values will be 081 * added to XML elements during the serialization process. And 082 * will be used to deserialize the object cycles fully. 083 */ 084 public CycleStrategy() { 085 this(MARK, REFER); 086 } 087 088 /** 089 * Constructor for the <code>CycleStrategy</code> object. This is 090 * used to create a strategy with the specified attributes, which 091 * will be added to serialized XML elements. These attributes 092 * are used to serialize the objects in such a way the cycles in 093 * the object graph can be deserialized and used fully. 094 * 095 * @param mark this is used to mark the identity of an object 096 * @param refer this is used to refer to an existing object 097 */ 098 public CycleStrategy(String mark, String refer) { 099 this(mark, refer, LABEL); 100 } 101 102 /** 103 * Constructor for the <code>CycleStrategy</code> object. This is 104 * used to create a strategy with the specified attributes, which 105 * will be added to serialized XML elements. These attributes 106 * are used to serialize the objects in such a way the cycles in 107 * the object graph can be deserialized and used fully. 108 * 109 * @param mark this is used to mark the identity of an object 110 * @param refer this is used to refer to an existing object 111 * @param label this is used to specify the class for the field 112 */ 113 public CycleStrategy(String mark, String refer, String label){ 114 this(mark, refer, label, LENGTH); 115 } 116 117 /** 118 * Constructor for the <code>CycleStrategy</code> object. This is 119 * used to create a strategy with the specified attributes, which 120 * will be added to serialized XML elements. These attributes 121 * are used to serialize the objects in such a way the cycles in 122 * the object graph can be deserialized and used fully. 123 * 124 * @param mark this is used to mark the identity of an object 125 * @param refer this is used to refer to an existing object 126 * @param label this is used to specify the class for the field 127 * @param length this is the length attribute used for arrays 128 */ 129 public CycleStrategy(String mark, String refer, String label, String length){ 130 this.contract = new Contract(mark, refer, label, length); 131 this.write = new WriteState(contract); 132 this.read = new ReadState(contract); 133 } 134 135 /** 136 * This method is used to read an object from the specified node. 137 * In order to get the root type the field and node map are 138 * specified. The field represents the annotated method or field 139 * within the deserialized object. The node map is used to get 140 * the attributes used to describe the objects identity, or in 141 * the case of an existing object it contains an object reference. 142 * 143 * @param type the method or field in the deserialized object 144 * @param node this is the XML element attributes to read 145 * @param map this is the session map used for deserialization 146 * 147 * @return this returns an instance to insert into the object 148 */ 149 public Value read(Type type, NodeMap node, Map map) throws Exception { 150 ReadGraph graph = read.find(map); 151 152 if(graph != null) { 153 return graph.read(type, node); 154 } 155 return null; 156 } 157 158 /** 159 * This is used to write the reference in to the XML element that 160 * is to be written. This will either insert an object identity if 161 * the object has not previously been written, or, if the object 162 * has already been written in a previous element, this will write 163 * the reference to that object. This allows all cycles within the 164 * graph to be serialized so that they can be fully deserialized. 165 * 166 * @param type the type of the field or method in the object 167 * @param value this is the actual object that is to be written 168 * @param node this is the XML element attribute map to use 169 * @param map this is the session map used for the serialization 170 * 171 * @return returns true if the object has been fully serialized 172 */ 173 public boolean write(Type type, Object value, NodeMap node, Map map){ 174 WriteGraph graph = write.find(map); 175 176 if(graph != null) { 177 return graph.write(type, value, node); 178 } 179 return false; 180 } 181}