private static <T> Field<T> createCollectionEnumV( int number, String name, final java.lang.reflect.Field f, final MessageFactory messageFactory, final Class<Object> genericType, IdStrategy strategy) { final EnumIO<?> eio = strategy.getEnumIO(genericType); return new Field<T>(FieldType.ENUM, number, name, true, f.getAnnotation(Tag.class)) { { f.setAccessible(true); } @SuppressWarnings("unchecked") protected void mergeFrom(Input input, T message) throws IOException { final Enum<?> value = eio.readFrom(input); try { final Collection<Enum<?>> existing = (Collection<Enum<?>>) f.get(message); if (existing == null) { final Collection<Enum<?>> collection = messageFactory.newMessage(); collection.add(value); f.set(message, collection); } else existing.add(value); } catch (IllegalArgumentException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } @SuppressWarnings("unchecked") protected void writeTo(Output output, T message) throws IOException { final Collection<Enum<?>> collection; try { collection = (Collection<Enum<?>>) f.get(message); } catch (IllegalArgumentException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } if (collection != null && !collection.isEmpty()) { for (Enum<?> en : collection) EnumIO.writeTo(output, number, true, en); } } protected void transfer(Pipe pipe, Input input, Output output, boolean repeated) throws IOException { EnumIO.transfer(pipe, input, output, number, repeated); } }; }
@SuppressWarnings("unchecked") static void writeObjectTo( Output output, Object value, Schema<?> currentSchema, IdStrategy strategy) throws IOException { if (Collections.class == value.getClass().getDeclaringClass()) { writeNonPublicCollectionTo(output, value, currentSchema, strategy); return; } if (EnumSet.class.isAssignableFrom(value.getClass())) { strategy.writeEnumIdTo(output, ID_ENUM_SET, EnumIO.getElementTypeFromEnumSet(value)); // TODO optimize } else { strategy.writeCollectionIdTo(output, ID_COLLECTION, value.getClass()); } if (output instanceof StatefulOutput) { // update using the derived schema. ((StatefulOutput) output).updateLast(strategy.COLLECTION_SCHEMA, currentSchema); } strategy.COLLECTION_SCHEMA.writeTo(output, (Collection<Object>) value); }
@SuppressWarnings("unchecked") public <T> Field<T> create( int number, String name, final java.lang.reflect.Field f, IdStrategy strategy) { if (null != f.getAnnotation(Morph.class)) { // can be used to override the configured system property: // RuntimeEnv.COLLECTION_SCHEMA_ON_REPEATED_FIELDS // In this context, Morph annotation will force using a // collection // schema only for this particular field. return RuntimeCollectionFieldFactory.getFactory().create(number, name, f, strategy); } if (EnumSet.class.isAssignableFrom(f.getType())) { final Class<Object> enumType = (Class<Object>) getGenericType(f, 0); if (enumType == null) { // still handle the serialization of EnumSets even without // generics return RuntimeFieldFactory.OBJECT.create(number, name, f, strategy); } return createCollectionEnumV( number, name, f, strategy.getEnumIO(enumType).getEnumSetFactory(), enumType, strategy); } final MessageFactory messageFactory = strategy.getCollectionFactory(f.getType()); final Class<Object> genericType = (Class<Object>) getGenericType(f, 0); if (genericType == null) { // the value is not a simple parameterized type. return createCollectionObjectV( number, name, f, messageFactory, genericType, PolymorphicSchemaFactories.OBJECT, strategy); } final Delegate<Object> inline = getDelegateOrInline(genericType, strategy); if (inline != null) return createCollectionInlineV(number, name, f, messageFactory, inline); if (Message.class.isAssignableFrom(genericType)) return createCollectionPojoV(number, name, f, messageFactory, genericType, strategy); if (genericType.isEnum()) return createCollectionEnumV(number, name, f, messageFactory, genericType, strategy); final PolymorphicSchema.Factory factory = PolymorphicSchemaFactories.getFactoryFromRepeatedValueGenericType(genericType); if (factory != null) { return createCollectionObjectV( number, name, f, messageFactory, genericType, factory, strategy); } if (pojo(genericType, f.getAnnotation(Morph.class), strategy)) return createCollectionPojoV(number, name, f, messageFactory, genericType, strategy); if (genericType.isInterface()) { return createCollectionObjectV( number, name, f, messageFactory, genericType, PolymorphicSchemaFactories.OBJECT, strategy); } return createCollectionPolymorphicV( number, name, f, messageFactory, genericType, strategy); }
private static <T> Field<T> createCollectionPojoV( int number, String name, final java.lang.reflect.Field f, final MessageFactory messageFactory, final Class<Object> genericType, IdStrategy strategy) { return new RuntimeMessageField<T, Object>( genericType, strategy.getSchemaWrapper(genericType, true), FieldType.MESSAGE, number, name, true, f.getAnnotation(Tag.class)) { { f.setAccessible(true); } @SuppressWarnings("unchecked") protected void mergeFrom(Input input, T message) throws IOException { final Object value = input.mergeObject(null, getSchema()); try { final Collection<Object> existing = (Collection<Object>) f.get(message); if (existing == null) { final Collection<Object> collection = messageFactory.newMessage(); collection.add(value); f.set(message, collection); } else existing.add(value); } catch (IllegalArgumentException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } @SuppressWarnings("unchecked") protected void writeTo(Output output, T message) throws IOException { final Collection<Object> collection; try { collection = (Collection<Object>) f.get(message); } catch (IllegalArgumentException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } if (collection != null && !collection.isEmpty()) { final Schema<Object> schema = getSchema(); for (Object o : collection) { if (o != null) output.writeObject(number, o, schema, true); } } } protected void transfer(Pipe pipe, Input input, Output output, boolean repeated) throws IOException { output.writeObject(number, pipe, getPipeSchema(), repeated); } }; }
@SuppressWarnings("unchecked") static Object readObjectFrom( Input input, Schema<?> schema, Object owner, IdStrategy strategy, final int number) throws IOException { final boolean graph = input instanceof GraphInput; Object ret = null; switch (number) { case ID_EMPTY_SET: if (0 != input.readUInt32()) throw new ProtostuffException("Corrupt input."); if (graph) { // update the actual reference. ((GraphInput) input).updateLast(Collections.EMPTY_SET, owner); } ret = Collections.EMPTY_SET; break; case ID_EMPTY_LIST: if (0 != input.readUInt32()) throw new ProtostuffException("Corrupt input."); if (graph) { // update the actual reference. ((GraphInput) input).updateLast(Collections.EMPTY_LIST, owner); } ret = Collections.EMPTY_LIST; break; case ID_SINGLETON_SET: { if (0 != input.readUInt32()) throw new ProtostuffException("Corrupt input."); final Object collection = iSingletonSet.newInstance(); if (graph) { // update the actual reference. ((GraphInput) input).updateLast(collection, owner); } final int next = input.readFieldNumber(schema); if (next == 0) { // null element return collection; } if (next != 1) throw new ProtostuffException("Corrupt input"); final Wrapper wrapper = new Wrapper(); Object element = input.mergeObject(wrapper, strategy.OBJECT_SCHEMA); if (!graph || !((GraphInput) input).isCurrentMessageReference()) element = wrapper.value; try { fSingletonSet_element.set(collection, element); } catch (Exception e) { throw new RuntimeException(e); } ret = collection; break; } case ID_SINGLETON_LIST: { if (0 != input.readUInt32()) throw new ProtostuffException("Corrupt input."); final Object collection = iSingletonList.newInstance(); if (graph) { // update the actual reference. ((GraphInput) input).updateLast(collection, owner); } final int next = input.readFieldNumber(schema); if (next == 0) { // null element return collection; } if (next != 1) throw new ProtostuffException("Corrupt input."); final Wrapper wrapper = new Wrapper(); Object element = input.mergeObject(wrapper, strategy.OBJECT_SCHEMA); if (!graph || !((GraphInput) input).isCurrentMessageReference()) element = wrapper.value; try { fSingletonList_element.set(collection, element); } catch (Exception e) { throw new RuntimeException(e); } ret = collection; break; } case ID_SET_FROM_MAP: { final Object collection = iSetFromMap.newInstance(); if (graph) { // update the actual reference. ((GraphInput) input).updateLast(collection, owner); } final Wrapper wrapper = new Wrapper(); Object m = input.mergeObject(wrapper, strategy.POLYMORPHIC_MAP_SCHEMA); if (!graph || !((GraphInput) input).isCurrentMessageReference()) m = wrapper.value; try { fSetFromMap_m.set(collection, m); fSetFromMap_s.set(collection, ((Map<?, ?>) m).keySet()); } catch (Exception e) { throw new RuntimeException(e); } ret = collection; break; } case ID_COPIES_LIST: { if (0 != input.readUInt32()) throw new ProtostuffException("Corrupt input."); final Object collection = iCopiesList.newInstance(); if (graph) { // update the actual reference. ((GraphInput) input).updateLast(collection, owner); } if (1 != input.readFieldNumber(schema)) throw new ProtostuffException("Corrupt input."); final int n = input.readUInt32(), next = input.readFieldNumber(schema); if (next == 0) { // null element try { fCopiesList_n.setInt(collection, n); } catch (Exception e) { throw new RuntimeException(e); } return collection; } if (next != 2) throw new ProtostuffException("Corrupt input."); final Wrapper wrapper = new Wrapper(); Object element = input.mergeObject(wrapper, strategy.OBJECT_SCHEMA); if (!graph || !((GraphInput) input).isCurrentMessageReference()) element = wrapper.value; try { fCopiesList_n.setInt(collection, n); fCopiesList_element.set(collection, element); } catch (Exception e) { throw new RuntimeException(e); } ret = collection; break; } case ID_UNMODIFIABLE_COLLECTION: ret = readUnmodifiableCollectionFrom( input, schema, owner, strategy, graph, iUnmodifiableCollection.newInstance(), false, false); break; case ID_UNMODIFIABLE_SET: ret = readUnmodifiableCollectionFrom( input, schema, owner, strategy, graph, iUnmodifiableSet.newInstance(), false, false); break; case ID_UNMODIFIABLE_SORTED_SET: ret = readUnmodifiableCollectionFrom( input, schema, owner, strategy, graph, iUnmodifiableSortedSet.newInstance(), true, false); break; case ID_UNMODIFIABLE_LIST: ret = readUnmodifiableCollectionFrom( input, schema, owner, strategy, graph, iUnmodifiableList.newInstance(), false, true); break; case ID_UNMODIFIABLE_RANDOM_ACCESS_LIST: ret = readUnmodifiableCollectionFrom( input, schema, owner, strategy, graph, iUnmodifiableRandomAccessList.newInstance(), false, true); break; case ID_SYNCHRONIZED_COLLECTION: ret = readSynchronizedCollectionFrom( input, schema, owner, strategy, graph, iSynchronizedCollection.newInstance(), false, false); break; case ID_SYNCHRONIZED_SET: ret = readSynchronizedCollectionFrom( input, schema, owner, strategy, graph, iSynchronizedSet.newInstance(), false, false); break; case ID_SYNCHRONIZED_SORTED_SET: ret = readSynchronizedCollectionFrom( input, schema, owner, strategy, graph, iSynchronizedSortedSet.newInstance(), true, false); break; case ID_SYNCHRONIZED_LIST: ret = readSynchronizedCollectionFrom( input, schema, owner, strategy, graph, iSynchronizedList.newInstance(), false, true); break; case ID_SYNCHRONIZED_RANDOM_ACCESS_LIST: ret = readSynchronizedCollectionFrom( input, schema, owner, strategy, graph, iSynchronizedRandomAccessList.newInstance(), false, true); break; case ID_CHECKED_COLLECTION: ret = readCheckedCollectionFrom( input, schema, owner, strategy, graph, iCheckedCollection.newInstance(), false, false); break; case ID_CHECKED_SET: ret = readCheckedCollectionFrom( input, schema, owner, strategy, graph, iCheckedSet.newInstance(), false, false); break; case ID_CHECKED_SORTED_SET: ret = readCheckedCollectionFrom( input, schema, owner, strategy, graph, iCheckedSortedSet.newInstance(), true, false); break; case ID_CHECKED_LIST: ret = readCheckedCollectionFrom( input, schema, owner, strategy, graph, iCheckedList.newInstance(), false, true); break; case ID_CHECKED_RANDOM_ACCESS_LIST: ret = readCheckedCollectionFrom( input, schema, owner, strategy, graph, iCheckedRandomAccessList.newInstance(), false, true); break; case ID_ENUM_SET: { final Collection<?> es = strategy.resolveEnumFrom(input).newEnumSet(); if (graph) { // update the actual reference. ((GraphInput) input).updateLast(es, owner); } // TODO enum schema strategy.COLLECTION_SCHEMA.mergeFrom(input, (Collection<Object>) es); return es; } case ID_COLLECTION: { final Collection<Object> collection = strategy.resolveCollectionFrom(input).newMessage(); if (graph) { // update the actual reference. ((GraphInput) input).updateLast(collection, owner); } strategy.COLLECTION_SCHEMA.mergeFrom(input, collection); return collection; } default: throw new ProtostuffException("Corrupt input."); } if (0 != input.readFieldNumber(schema)) throw new ProtostuffException("Corrupt input."); return ret; }
static void transferObject( Pipe.Schema<Object> pipeSchema, Pipe pipe, Input input, Output output, IdStrategy strategy, final int number) throws IOException { switch (number) { case ID_EMPTY_SET: output.writeUInt32(number, input.readUInt32(), false); break; case ID_EMPTY_LIST: output.writeUInt32(number, input.readUInt32(), false); break; case ID_SINGLETON_SET: case ID_SINGLETON_LIST: { output.writeUInt32(number, input.readUInt32(), false); final int next = input.readFieldNumber(pipeSchema.wrappedSchema); if (next == 0) { // null element return; } if (next != 1) throw new ProtostuffException("Corrupt input."); output.writeObject(1, pipe, strategy.OBJECT_PIPE_SCHEMA, false); break; } case ID_SET_FROM_MAP: output.writeObject(number, pipe, strategy.POLYMORPHIC_MAP_PIPE_SCHEMA, false); break; case ID_COPIES_LIST: { output.writeUInt32(number, input.readUInt32(), false); if (1 != input.readFieldNumber(pipeSchema.wrappedSchema)) throw new ProtostuffException("Corrupt input."); // size output.writeUInt32(1, input.readUInt32(), false); final int next = input.readFieldNumber(pipeSchema.wrappedSchema); if (next == 0) { // null element return; } if (next != 2) throw new ProtostuffException("Corrupt input."); output.writeObject(2, pipe, strategy.OBJECT_PIPE_SCHEMA, false); break; } case ID_UNMODIFIABLE_COLLECTION: case ID_UNMODIFIABLE_SET: case ID_UNMODIFIABLE_SORTED_SET: case ID_UNMODIFIABLE_LIST: case ID_UNMODIFIABLE_RANDOM_ACCESS_LIST: output.writeObject(number, pipe, strategy.POLYMORPHIC_COLLECTION_PIPE_SCHEMA, false); break; case ID_SYNCHRONIZED_COLLECTION: case ID_SYNCHRONIZED_SET: case ID_SYNCHRONIZED_SORTED_SET: case ID_SYNCHRONIZED_LIST: case ID_SYNCHRONIZED_RANDOM_ACCESS_LIST: output.writeObject(number, pipe, strategy.POLYMORPHIC_COLLECTION_PIPE_SCHEMA, false); break; case ID_CHECKED_COLLECTION: case ID_CHECKED_SET: case ID_CHECKED_SORTED_SET: case ID_CHECKED_LIST: case ID_CHECKED_RANDOM_ACCESS_LIST: output.writeObject(number, pipe, strategy.POLYMORPHIC_COLLECTION_PIPE_SCHEMA, false); if (1 != input.readFieldNumber(pipeSchema.wrappedSchema)) throw new ProtostuffException("Corrupt input."); output.writeObject(1, pipe, strategy.CLASS_PIPE_SCHEMA, false); break; case ID_ENUM_SET: strategy.transferEnumId(input, output, number); if (output instanceof StatefulOutput) { // update using the derived schema. ((StatefulOutput) output).updateLast(strategy.COLLECTION_PIPE_SCHEMA, pipeSchema); } // TODO use enum schema Pipe.transferDirect(strategy.COLLECTION_PIPE_SCHEMA, pipe, input, output); return; case ID_COLLECTION: strategy.transferCollectionId(input, output, number); if (output instanceof StatefulOutput) { // update using the derived schema. ((StatefulOutput) output).updateLast(strategy.COLLECTION_PIPE_SCHEMA, pipeSchema); } Pipe.transferDirect(strategy.COLLECTION_PIPE_SCHEMA, pipe, input, output); return; default: throw new ProtostuffException("Corrupt input."); } if (0 != input.readFieldNumber(pipeSchema.wrappedSchema)) throw new ProtostuffException("Corrupt input."); }