| 1 | /* |
| 2 | * This file is part of JON. |
| 3 | * |
| 4 | * JON is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU Lesser General Public License as published by |
| 6 | * the Free Software Foundation; either version 3 of the License, or |
| 7 | * (at your option) any later version. |
| 8 | * |
| 9 | * JON is distributed in the hope that it will be useful, |
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | * GNU Lesser General Public License for more details. |
| 13 | * |
| 14 | * You should have received a copy of the GNU Lesser General Public License |
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 16 | * |
| 17 | * Copyright 2007 Michael Doberenz |
| 18 | */ |
| 19 | package org.fuwjax.jon.accessor; |
| 20 | |
| 21 | import org.fuwjax.jon.CachedAppendable; |
| 22 | import org.fuwjax.jon.CachedLexable; |
| 23 | import org.fuwjax.jon.ClassCastStrategy; |
| 24 | import org.fuwjax.jon.IndirectType; |
| 25 | import org.fuwjax.jon.ObjectAccessException; |
| 26 | import org.fuwjax.jon.Reference; |
| 27 | import org.fuwjax.jon.ReferenceExistsException; |
| 28 | import org.fuwjax.jon.ReferenceStrategy; |
| 29 | import org.fuwjax.jon.SerialFormatException; |
| 30 | |
| 31 | /** |
| 32 | * Contains the format for turning a particular kind of datatype into a string. |
| 33 | * @author michaeldoberenz |
| 34 | */ |
| 35 | public enum Symbol{ |
| 36 | /** |
| 37 | * The root symbol for this symbol spec. |
| 38 | */ |
| 39 | Element{ |
| 40 | @Override |
| 41 | public void write(final CachedAppendable writer, final Object object, final Accessor accessor) |
| 42 | throws ObjectAccessException, SerialFormatException{ |
| 43 | final IndirectType type = safeCast(IndirectType.class, accessor); |
| 44 | final IndirectType actualType = type.getActualType(object); |
| 45 | final ReferenceStrategy refStrategy = actualType.getReferenceStrategy(); |
| 46 | try{ |
| 47 | refStrategy.write(writer, object); |
| 48 | final ClassCastStrategy castStrategy = actualType.getClassCastStrategy(); |
| 49 | castStrategy.write(writer, actualType, type); |
| 50 | final Symbol spec = actualType.getSymbolSpec(); |
| 51 | spec.write(writer, object, actualType); |
| 52 | }catch(ReferenceExistsException e){ |
| 53 | // continue |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | @Override |
| 58 | public Object read(final CachedLexable lexer, final Object object, final Accessor accessor) |
| 59 | throws ObjectAccessException, SerialFormatException{ |
| 60 | final IndirectType type = safeCast(IndirectType.class, accessor); |
| 61 | try{ |
| 62 | final Reference ref = ReferenceStrategy.read(lexer); |
| 63 | final IndirectType actualType = ClassCastStrategy.read(lexer, type); |
| 64 | final Symbol spec = actualType.getSymbolSpec(); |
| 65 | final Object ret = spec.read(lexer, object, actualType); |
| 66 | ref.store(ret); |
| 67 | return ret; |
| 68 | }catch(ReferenceExistsException e){ |
| 69 | return e.getStoredObject(); |
| 70 | } |
| 71 | } |
| 72 | }, |
| 73 | /** |
| 74 | * The Object symbol for the JON format. |
| 75 | */ |
| 76 | Object{ |
| 77 | @Override |
| 78 | public void write(final CachedAppendable writer, final Object object, final Accessor accessor) |
| 79 | throws ObjectAccessException, SerialFormatException{ |
| 80 | final ObjectAccessor type = safeCast(ObjectAccessor.class, accessor); |
| 81 | Token.ObjectStart.write(writer); |
| 82 | type.writePartitions(new ListWriter(writer, Token.PartitionSeparator, Entries), object); |
| 83 | Token.ObjectStop.write(writer); |
| 84 | } |
| 85 | |
| 86 | @Override |
| 87 | public Object read(final CachedLexable lexer, final Object object, final Accessor accessor) |
| 88 | throws ObjectAccessException, SerialFormatException{ |
| 89 | final ObjectAccessor type = safeCast(ObjectAccessor.class, accessor); |
| 90 | Token.ObjectStart.read(lexer); |
| 91 | final Object container = type.createContainer(object); |
| 92 | type.readPartitions(new ListReader(lexer, Token.PartitionSeparator, Entries), container); |
| 93 | Token.ObjectStop.read(lexer); |
| 94 | return type.createInstance(container, object); |
| 95 | } |
| 96 | }, |
| 97 | /** |
| 98 | * The format for a class cast. |
| 99 | */ |
| 100 | ClassCast{ |
| 101 | @Override |
| 102 | public void write(final CachedAppendable writer, final Object object, final Accessor accessor) |
| 103 | throws ObjectAccessException, SerialFormatException{ |
| 104 | final IndirectType type = safeCast(IndirectType.class, accessor); |
| 105 | Token.ClassCastStart.write(writer); |
| 106 | Element.write(writer, object, type); |
| 107 | Token.ClassCastStop.write(writer); |
| 108 | } |
| 109 | |
| 110 | @Override |
| 111 | public Object read(final CachedLexable lexer, final Object object, final Accessor accessor) |
| 112 | throws ObjectAccessException, SerialFormatException{ |
| 113 | final IndirectType type = safeCast(IndirectType.class, accessor); |
| 114 | Token.ClassCastStart.read(lexer); |
| 115 | final Class<?> className = (Class<?>)Element.read(lexer, null, type); |
| 116 | Token.ClassCastStop.read(lexer); |
| 117 | return type.getIndirectType(className); |
| 118 | } |
| 119 | }, |
| 120 | /** |
| 121 | * the format for a reference value. |
| 122 | */ |
| 123 | Literal{ |
| 124 | @Override |
| 125 | public void write(final CachedAppendable writer, final Object object, final Accessor accessor) |
| 126 | throws ObjectAccessException, SerialFormatException{ |
| 127 | final LiteralAccessor type = safeCast(LiteralAccessor.class, accessor); |
| 128 | type.getLiteral().write(writer, object, type); |
| 129 | } |
| 130 | |
| 131 | @Override |
| 132 | public Object read(final CachedLexable lexer, final Object object, final Accessor accessor) |
| 133 | throws ObjectAccessException, SerialFormatException{ |
| 134 | final LiteralAccessor type = safeCast(LiteralAccessor.class, accessor); |
| 135 | return type.getLiteral().read(lexer, object, type); |
| 136 | } |
| 137 | }, |
| 138 | /** |
| 139 | * the format for a field identifier. |
| 140 | */ |
| 141 | Elements{ |
| 142 | @Override |
| 143 | public void write(final CachedAppendable writer, final Object object, final Accessor accessor) |
| 144 | throws ObjectAccessException, SerialFormatException{ |
| 145 | final ElementsAccessor type = safeCast(ElementsAccessor.class, accessor); |
| 146 | type.writeElements(new ListWriter(writer, Token.ElementSeparator), object); |
| 147 | } |
| 148 | |
| 149 | @Override |
| 150 | public Object read(final CachedLexable lexer, final Object object, final Accessor accessor) |
| 151 | throws ObjectAccessException, SerialFormatException{ |
| 152 | final ElementsAccessor type = safeCast(ElementsAccessor.class, accessor); |
| 153 | type.readElements(new ListReader(lexer, Token.ElementSeparator), object); |
| 154 | return object; |
| 155 | } |
| 156 | }, |
| 157 | /** |
| 158 | * the format for a List symbol. |
| 159 | */ |
| 160 | List{ |
| 161 | @Override |
| 162 | public void write(final CachedAppendable writer, final Object object, final Accessor accessor) |
| 163 | throws ObjectAccessException, SerialFormatException{ |
| 164 | Token.ListStart.write(writer); |
| 165 | Elements.write(writer, object, accessor); |
| 166 | Token.ListStop.write(writer); |
| 167 | } |
| 168 | |
| 169 | @Override |
| 170 | public Object read(final CachedLexable lexer, final Object object, final Accessor accessor) |
| 171 | throws ObjectAccessException, SerialFormatException{ |
| 172 | final ListAccessor type = safeCast(ListAccessor.class, accessor); |
| 173 | Token.ListStart.read(lexer); |
| 174 | final Object container = type.createContainer(object); |
| 175 | Elements.read(lexer, container, accessor); |
| 176 | Token.ListStop.read(lexer); |
| 177 | return type.createInstance(container, object); |
| 178 | } |
| 179 | }, |
| 180 | /** |
| 181 | * the format for a Map symbol. |
| 182 | */ |
| 183 | Entries{ |
| 184 | @Override |
| 185 | public void write(final CachedAppendable writer, final Object object, final Accessor accessor) |
| 186 | throws ObjectAccessException, SerialFormatException{ |
| 187 | final EntriesAccessor type = safeCast(EntriesAccessor.class, accessor); |
| 188 | type.writeEntries(new KeyValueWriter(writer, Token.EntrySeparator, Token.KeyValueSeparator), object); |
| 189 | } |
| 190 | |
| 191 | @Override |
| 192 | public Object read(final CachedLexable lexer, final Object object, final Accessor accessor) |
| 193 | throws ObjectAccessException, SerialFormatException{ |
| 194 | final EntriesAccessor type = safeCast(EntriesAccessor.class, accessor); |
| 195 | type.readEntries(new KeyValueReader(lexer, Token.EntrySeparator, Token.KeyValueSeparator), object); |
| 196 | return object; |
| 197 | } |
| 198 | }; |
| 199 | /** |
| 200 | * Serializes the given object to the specified appender. |
| 201 | * @param writer the destination for the formatted output. |
| 202 | * @param object the object to flatten into this specification. |
| 203 | * @param type the expected type of <code>object</code> |
| 204 | * @throws ObjectAccessException if an object relationship cannot be followed |
| 205 | * @throws SerialFormatException if the JON format cannot be preserved |
| 206 | */ |
| 207 | public abstract void write(CachedAppendable writer, Object object, Accessor type) throws ObjectAccessException, |
| 208 | SerialFormatException; |
| 209 | |
| 210 | /** |
| 211 | * Deserializes the next object of type <code>type</code> from |
| 212 | * <code>lexer</code> into <code>object</code>. |
| 213 | * @param lexer the source of the formatted input. |
| 214 | * @param object the object to use as storage for the deserialized data |
| 215 | * @param type the expected type of <code>object</code> |
| 216 | * @return the deserialized object |
| 217 | * @throws ObjectAccessException if an object relationship cannot be restored |
| 218 | * @throws SerialFormatException if the JON format has not been observed |
| 219 | */ |
| 220 | public abstract Object read(CachedLexable lexer, Object object, Accessor type) throws ObjectAccessException, |
| 221 | SerialFormatException; |
| 222 | |
| 223 | /** |
| 224 | * Allows the safe cast of <code>accessor</code> from Accessor to the type |
| 225 | * represented by <code>cls</code>. |
| 226 | * @param <A> the type of the resulting cast |
| 227 | * @param cls the class instance of the type of the resulting cast |
| 228 | * @param accessor the object to cast |
| 229 | * @return the safely cast <code>accessor</code> |
| 230 | */ |
| 231 | static <A extends Accessor>A safeCast(final Class<A> cls, final Accessor accessor){ |
| 232 | return cls.cast(accessor); |
| 233 | } |
| 234 | } |