ignite-950: implementing marshal aware
Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/5749b068 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/5749b068 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/5749b068 Branch: refs/heads/ignite-950 Commit: 5749b068d623072299b46eb1fb099c8e3636d5ee Parents: d9f85e6 Author: Denis Magda <dma...@gridgain.com> Authored: Tue Jun 23 16:51:33 2015 +0300 Committer: Denis Magda <dma...@gridgain.com> Committed: Tue Jun 23 16:51:33 2015 +0300 ---------------------------------------------------------------------- .../org/apache/ignite/internal/IgnitionEx.java | 1 - .../cache/CacheIndexedObjectImpl.java | 2 +- .../cacheobject/IgniteCacheObjectProcessor.java | 2 +- .../IgniteCacheObjectProcessorImpl.java | 3 +- .../optimized/OptimizedClassDescriptor.java | 38 +- .../optimized/OptimizedFieldsReader.java | 196 ++++++++++ .../optimized/OptimizedFieldsWriter.java | 196 ++++++++++ .../optimized/OptimizedMarshalAware.java | 52 +++ .../OptimizedMarshalAwareMetaCollector.java | 179 +++++++++ .../optimized/OptimizedMarshallerExt.java | 357 +++++++++++++++++ .../OptimizedMarshallerMetaHandler.java | 40 ++ .../optimized/OptimizedMarshallerUtils.java | 3 + .../optimized/OptimizedObjectInputStream.java | 392 ++++++++++++++++++- .../OptimizedObjectInputStreamExt.java | 51 +++ .../optimized/OptimizedObjectMetadata.java | 172 ++++++++ .../optimized/OptimizedObjectMetadataKey.java | 70 ++++ .../optimized/OptimizedObjectOutputStream.java | 209 +++++++++- .../OptimizedObjectOutputStreamExt.java | 152 +++++++ .../OptimizedObjectStreamExtRegistry.java | 225 +++++++++++ .../optimized/ext/OptimizedMarshallerExt.java | 353 ----------------- .../ext/OptimizedMarshallerExtMetaHandler.java | 40 -- .../ext/OptimizedObjectInputStreamExt.java | 241 ------------ .../optimized/ext/OptimizedObjectMetadata.java | 157 -------- .../ext/OptimizedObjectMetadataKey.java | 70 ---- .../ext/OptimizedObjectOutputStreamExt.java | 179 --------- .../ext/OptimizedObjectStreamExtRegistry.java | 226 ----------- .../marshaller/optimized/ext/package-info.java | 21 - .../ext/OptimizedMarshallerExtSelfTest.java | 75 +++- .../junits/IgniteTestResources.java | 1 - ...acheOptimizedMarshallerExtQuerySelfTest.java | 4 +- 30 files changed, 2405 insertions(+), 1302 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5749b068/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java index 422f517..7356d85 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java @@ -32,7 +32,6 @@ import org.apache.ignite.logger.java.*; import org.apache.ignite.marshaller.*; import org.apache.ignite.marshaller.jdk.*; import org.apache.ignite.marshaller.optimized.*; -import org.apache.ignite.marshaller.optimized.ext.*; import org.apache.ignite.mxbean.*; import org.apache.ignite.plugin.segmentation.*; import org.apache.ignite.resources.*; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5749b068/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheIndexedObjectImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheIndexedObjectImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheIndexedObjectImpl.java index 58e9c97..47b83ae 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheIndexedObjectImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheIndexedObjectImpl.java @@ -20,7 +20,7 @@ package org.apache.ignite.internal.processors.cache; import org.apache.ignite.*; import org.apache.ignite.internal.util.*; import org.apache.ignite.internal.util.typedef.internal.*; -import org.apache.ignite.marshaller.optimized.ext.*; +import org.apache.ignite.marshaller.optimized.*; import org.apache.ignite.plugin.extensions.communication.*; import org.jetbrains.annotations.*; import sun.misc.*; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5749b068/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessor.java index 42ccbce..a4964b2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessor.java @@ -22,7 +22,7 @@ import org.apache.ignite.configuration.*; import org.apache.ignite.internal.*; import org.apache.ignite.internal.processors.*; import org.apache.ignite.internal.processors.cache.*; -import org.apache.ignite.marshaller.optimized.ext.*; +import org.apache.ignite.marshaller.optimized.*; import org.jetbrains.annotations.*; /** http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5749b068/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessorImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessorImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessorImpl.java index 6ae958a..d29b64a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessorImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessorImpl.java @@ -29,7 +29,6 @@ import org.apache.ignite.internal.util.typedef.internal.*; import org.apache.ignite.lang.*; import org.apache.ignite.marshaller.*; import org.apache.ignite.marshaller.optimized.*; -import org.apache.ignite.marshaller.optimized.ext.*; import org.jetbrains.annotations.*; import java.math.*; @@ -90,7 +89,7 @@ public class IgniteCacheObjectProcessorImpl extends GridProcessorAdapter impleme if (marsh instanceof OptimizedMarshallerExt) { optMarshExt = (OptimizedMarshallerExt)marsh; - OptimizedMarshallerExtMetaHandler metaHandler = new OptimizedMarshallerExtMetaHandler() { + OptimizedMarshallerMetaHandler metaHandler = new OptimizedMarshallerMetaHandler() { @Override public void addMeta(int typeId, OptimizedObjectMetadata meta) { if (metaBuf.contains(typeId)) return; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5749b068/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java index d77551f..126568e 100644 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java @@ -329,6 +329,21 @@ public class OptimizedClassDescriptor { throw new IOException("Externalizable class doesn't have default constructor: " + cls, e); } } + else if (OptimizedMarshalAware.class.isAssignableFrom(cls)) { + type = MARSHAL_AWARE; + + try { + constructor = !Modifier.isStatic(cls.getModifiers()) && cls.getDeclaringClass() != null ? + cls.getDeclaredConstructor(cls.getDeclaringClass()) : + cls.getDeclaredConstructor(); + + constructor.setAccessible(true); + } + catch (NoSuchMethodException e) { + throw new IOException("OptimizedMarshalAware class doesn't have default constructor: " + cls, + e); + } + } else { type = SERIALIZABLE; @@ -408,8 +423,6 @@ public class OptimizedClassDescriptor { isPrivate(mod) && isStatic(mod) && isFinal(mod)) { hasSerialPersistentFields = true; - fieldsIndexingSupported = false; - serFieldsDesc.setAccessible(true); ObjectStreamField[] serFields = (ObjectStreamField[]) serFieldsDesc.get(null); @@ -718,6 +731,22 @@ public class OptimizedClassDescriptor { break; + case MARSHAL_AWARE: + writeTypeData(out); + + out.writeShort(checksum); + out.writeMarshalAware(obj); + + if (out.metaHandler.metadata(typeId) == null) { + OptimizedMarshalAwareMetaCollector collector = new OptimizedMarshalAwareMetaCollector(); + + ((OptimizedMarshalAware)obj).writeFields(collector); + + out.metaHandler.addMeta(typeId, collector.meta()); + } + + break; + case SERIALIZABLE: if (out.requireSerializable() && !isSerial) throw new NotSerializableException("Must implement java.io.Serializable or " + @@ -770,6 +799,11 @@ public class OptimizedClassDescriptor { return in.readSerializable(cls, readObjMtds, readResolveMtd, fields); + case MARSHAL_AWARE: + verifyChecksum(in.readShort()); + + return in.readMarshalAware(constructor, readResolveMtd); + default: assert false : "Unexpected type: " + type; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5749b068/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedFieldsReader.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedFieldsReader.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedFieldsReader.java new file mode 100644 index 0000000..57a59ed --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedFieldsReader.java @@ -0,0 +1,196 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.marshaller.optimized; + +import org.jetbrains.annotations.*; + +import java.io.*; +import java.util.*; + +/** + * TODO: IGNITE-950 + */ +public interface OptimizedFieldsReader { + /** + * @param fieldName Field name. + * @return Byte value. + * @throws IOException In case of error. + */ + public byte readByte(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Short value. + * @throws IOException In case of error. + */ + public short readShort(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Integer value. + * @throws IOException In case of error. + */ + public int readInt(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Long value. + * @throws IOException In case of error. + */ + public long readLong(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @throws IOException In case of error. + * @return Float value. + */ + public float readFloat(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Double value. + * @throws IOException In case of error. + */ + public double readDouble(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Char value. + * @throws IOException In case of error. + */ + public char readChar(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Boolean value. + * @throws IOException In case of error. + */ + public boolean readBoolean(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return String value. + * @throws IOException In case of error. + */ + @Nullable public String readString(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Object. + * @throws IOException In case of error. + */ + @Nullable public <T> T readObject(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Byte array. + * @throws IOException In case of error. + */ + @Nullable public byte[] readByteArray(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Short array. + * @throws IOException In case of error. + */ + @Nullable public short[] readShortArray(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Integer array. + * @throws IOException In case of error. + */ + @Nullable public int[] readIntArray(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Long array. + * @throws IOException In case of error. + */ + @Nullable public long[] readLongArray(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Float array. + * @throws IOException In case of error. + */ + @Nullable public float[] readFloatArray(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Byte array. + * @throws IOException In case of error. + */ + @Nullable public double[] readDoubleArray(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Char array. + * @throws IOException In case of error. + */ + @Nullable public char[] readCharArray(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Boolean array. + * @throws IOException In case of error. + */ + @Nullable public boolean[] readBooleanArray(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return String array. + * @throws IOException In case of error. + */ + @Nullable public String[] readStringArray(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Object array. + * @throws IOException In case of error. + */ + @Nullable public Object[] readObjectArray(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Collection. + * @throws IOException In case of error. + */ + @Nullable public <T> Collection<T> readCollection(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Map. + * @throws IOException In case of error. + */ + @Nullable public <K, V> Map<K, V> readMap(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Value. + * @throws IOException In case of error. + */ + @Nullable public <T extends Enum<?>> T readEnum(String fieldName) throws IOException; + + /** + * @param fieldName Field name. + * @return Value. + * @throws IOException In case of error. + */ + @Nullable public <T extends Enum<?>> T[] readEnumArray(String fieldName) throws IOException; +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5749b068/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedFieldsWriter.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedFieldsWriter.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedFieldsWriter.java new file mode 100644 index 0000000..f104fba --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedFieldsWriter.java @@ -0,0 +1,196 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.marshaller.optimized; + +import org.jetbrains.annotations.*; + +import java.io.*; +import java.util.*; + +/** + * TODO: IGNITE-950 + */ +public interface OptimizedFieldsWriter { + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeByte(String fieldName, byte val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeShort(String fieldName, short val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeInt(String fieldName, int val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeLong(String fieldName, long val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeFloat(String fieldName, float val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeDouble(String fieldName, double val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeChar(String fieldName, char val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeBoolean(String fieldName, boolean val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeString(String fieldName, @Nullable String val) throws IOException; + + /** + * @param fieldName Field name. + * @param obj Value to write. + * @throws IOException In case of error. + */ + public void writeObject(String fieldName, @Nullable Object obj) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeByteArray(String fieldName, @Nullable byte[] val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeShortArray(String fieldName, @Nullable short[] val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeIntArray(String fieldName, @Nullable int[] val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeLongArray(String fieldName, @Nullable long[] val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeFloatArray(String fieldName, @Nullable float[] val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeDoubleArray(String fieldName, @Nullable double[] val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeCharArray(String fieldName, @Nullable char[] val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeBooleanArray(String fieldName, @Nullable boolean[] val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeStringArray(String fieldName, @Nullable String[] val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public void writeObjectArray(String fieldName, @Nullable Object[] val) throws IOException; + + /** + * @param fieldName Field name. + * @param col Collection to write. + * @throws IOException In case of error. + */ + public <T> void writeCollection(String fieldName, @Nullable Collection<T> col) throws IOException; + + /** + * @param fieldName Field name. + * @param map Map to write. + * @throws IOException In case of error. + */ + public <K, V> void writeMap(String fieldName, @Nullable Map<K, V> map) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public <T extends Enum<?>> void writeEnum(String fieldName, T val) throws IOException; + + /** + * @param fieldName Field name. + * @param val Value to write. + * @throws IOException In case of error. + */ + public <T extends Enum<?>> void writeEnumArray(String fieldName, T[] val) throws IOException; +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5749b068/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshalAware.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshalAware.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshalAware.java new file mode 100644 index 0000000..cc90cff --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshalAware.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.marshaller.optimized; + +import java.io.*; + +/** + * TODO: IGNITE-950 + * + * Interface that allows to implement custom serialization + * logic for portable objects. Portable objects are not required + * to implement this interface, in which case Ignite will automatically + * serialize portable objects using reflection. + * <p> + * This interface, in a way, is analogous to {@link java.io.Externalizable} + * interface, which allows users to override default serialization logic, + * usually for performance reasons. The only difference here is that portable + * serialization is already very fast and implementing custom serialization + * logic for portables does not provide significant performance gains. + */ +public interface OptimizedMarshalAware { + /** + * Writes fields to provided writer. + * + * @param writer Fields writer. + * @throws IOException In case of error. + */ + public void writeFields(OptimizedFieldsWriter writer) throws IOException; + + /** + * Reads fields from provided reader. + * + * @param reader Fields reader. + * @throws IOException In case of error. + */ + public void readFields(OptimizedFieldsReader reader) throws IOException; +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5749b068/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshalAwareMetaCollector.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshalAwareMetaCollector.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshalAwareMetaCollector.java new file mode 100644 index 0000000..c4fb9d4 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshalAwareMetaCollector.java @@ -0,0 +1,179 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.marshaller.optimized; + +import org.jetbrains.annotations.*; + +import java.io.*; +import java.util.*; + +import static org.apache.ignite.marshaller.optimized.OptimizedFieldType.*; + +/** + * TODO: IGNITE-950 + */ +class OptimizedMarshalAwareMetaCollector implements OptimizedFieldsWriter { + /** */ + private OptimizedObjectMetadata meta; + + /** + * Constructor. + */ + public OptimizedMarshalAwareMetaCollector() { + meta = new OptimizedObjectMetadata(); + } + + /** {@inheritDoc} */ + @Override public void writeByte(String fieldName, byte val) throws IOException { + putFieldToMeta(fieldName, BYTE); + } + + /** {@inheritDoc} */ + @Override public void writeShort(String fieldName, short val) throws IOException { + putFieldToMeta(fieldName, SHORT); + } + + /** {@inheritDoc} */ + @Override public void writeInt(String fieldName, int val) throws IOException { + putFieldToMeta(fieldName, INT); + } + + /** {@inheritDoc} */ + @Override public void writeLong(String fieldName, long val) throws IOException { + putFieldToMeta(fieldName, LONG); + } + + /** {@inheritDoc} */ + @Override public void writeFloat(String fieldName, float val) throws IOException { + putFieldToMeta(fieldName, FLOAT); + } + + /** {@inheritDoc} */ + @Override public void writeDouble(String fieldName, double val) throws IOException { + putFieldToMeta(fieldName, DOUBLE); + } + + /** {@inheritDoc} */ + @Override public void writeChar(String fieldName, char val) throws IOException { + putFieldToMeta(fieldName, CHAR); + } + + /** {@inheritDoc} */ + @Override public void writeBoolean(String fieldName, boolean val) throws IOException { + putFieldToMeta(fieldName, BOOLEAN); + } + + /** {@inheritDoc} */ + @Override public void writeString(String fieldName, @Nullable String val) throws IOException { + putFieldToMeta(fieldName, OTHER); + } + + /** {@inheritDoc} */ + @Override public void writeObject(String fieldName, @Nullable Object obj) throws IOException { + putFieldToMeta(fieldName, OTHER); + } + + /** {@inheritDoc} */ + @Override public void writeByteArray(String fieldName, @Nullable byte[] val) throws IOException { + putFieldToMeta(fieldName, OTHER); + } + + /** {@inheritDoc} */ + @Override public void writeShortArray(String fieldName, @Nullable short[] val) throws IOException { + putFieldToMeta(fieldName, OTHER); + } + + /** {@inheritDoc} */ + @Override public void writeIntArray(String fieldName, @Nullable int[] val) throws IOException { + putFieldToMeta(fieldName, OTHER); + } + + /** {@inheritDoc} */ + @Override public void writeLongArray(String fieldName, @Nullable long[] val) throws IOException { + putFieldToMeta(fieldName, OTHER); + } + + /** {@inheritDoc} */ + @Override public void writeFloatArray(String fieldName, @Nullable float[] val) throws IOException { + putFieldToMeta(fieldName, OTHER); + } + + /** {@inheritDoc} */ + @Override public void writeDoubleArray(String fieldName, @Nullable double[] val) throws IOException { + putFieldToMeta(fieldName, OTHER); + } + + /** {@inheritDoc} */ + @Override public void writeCharArray(String fieldName, @Nullable char[] val) throws IOException { + putFieldToMeta(fieldName, OTHER); + } + + /** {@inheritDoc} */ + @Override public void writeBooleanArray(String fieldName, @Nullable boolean[] val) throws IOException { + putFieldToMeta(fieldName, OTHER); + } + + /** {@inheritDoc} */ + @Override public void writeStringArray(String fieldName, @Nullable String[] val) throws IOException { + putFieldToMeta(fieldName, OTHER); + } + + /** {@inheritDoc} */ + @Override public void writeObjectArray(String fieldName, @Nullable Object[] val) throws IOException { + putFieldToMeta(fieldName, OTHER); + } + + /** {@inheritDoc} */ + @Override public <T> void writeCollection(String fieldName, @Nullable Collection<T> col) throws IOException { + putFieldToMeta(fieldName, OTHER); + } + + /** {@inheritDoc} */ + @Override public <K, V> void writeMap(String fieldName, @Nullable Map<K, V> map) throws IOException { + putFieldToMeta(fieldName, OTHER); + } + + /** {@inheritDoc} */ + @Override public <T extends Enum<?>> void writeEnum(String fieldName, T val) throws IOException { + putFieldToMeta(fieldName, OTHER); + } + + /** {@inheritDoc} */ + @Override public <T extends Enum<?>> void writeEnumArray(String fieldName, T[] val) throws IOException { + putFieldToMeta(fieldName, OTHER); + } + + /** + * Returns gather metadata. + * + * @return Metadata. + */ + OptimizedObjectMetadata meta() { + return meta; + } + + /** + * Adds field to the metadata. + * + * @param fieldName Field name. + * @param type Field type. + */ + private void putFieldToMeta(String fieldName, OptimizedFieldType type) { + meta.addMeta(OptimizedMarshallerUtils.resolveFieldId(fieldName), type); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5749b068/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerExt.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerExt.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerExt.java new file mode 100644 index 0000000..7d90581 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerExt.java @@ -0,0 +1,357 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.marshaller.optimized; + +import org.apache.ignite.*; +import org.apache.ignite.internal.processors.cache.*; +import org.jetbrains.annotations.*; + +import java.io.*; + +import static org.apache.ignite.marshaller.optimized.OptimizedClassDescriptor.*; + +/** + * TODO + */ +public class OptimizedMarshallerExt extends OptimizedMarshaller { + /** */ + static final byte EMPTY_FOOTER = -1; + + /** */ + static final byte FOOTER_LEN_OFF = 2; + + /** */ + static final int FOOTER_BODY_LEN_MASK = 0x3FFFFFFF; + + /** */ + static final int FOOTER_BODY_IS_HANDLE_MASK = 0x40000000; + + /** */ + static final byte FOOTER_BODY_HANDLE_MASK_BIT = 30; + + /** */ + public static final byte VARIABLE_LEN = -1; + + /** */ + private volatile OptimizedMarshallerMetaHandler metaHandler; + + /** + * Creates new marshaller will all defaults. + * + * @throws IgniteException If this marshaller is not supported on the current JVM. + */ + public OptimizedMarshallerExt() { + // No-op + } + + /** + * Creates new marshaller providing whether it should + * require {@link Serializable} interface or not. + * + * @param requireSer Whether to require {@link Serializable}. + */ + public OptimizedMarshallerExt(boolean requireSer) { + super(requireSer); + } + + /** + * Sets metadata handler. + * + * @param metaHandler Metadata handler. + */ + public void setMetadataHandler(OptimizedMarshallerMetaHandler metaHandler) { + this.metaHandler = metaHandler; + } + + /** + * Returns currently set ID mapper. + * + * @return ID mapper. + */ + public OptimizedMarshallerIdMapper idMapper() { + return mapper; + } + + /** + * Enables fields indexing for the object of the given {@code cls}. + * + * If enabled then a footer will be added during marshalling of an object of the given {@code cls} to the end of + * its serialized form. + * + * @param cls Class. + * @return {@code true} if fields indexing is enabled. + * @throws IgniteCheckedException In case of error. + */ + public boolean enableFieldsIndexing(Class<?> cls) throws IgniteCheckedException { + assert metaHandler != null; + + if (ctx.isSystemType(cls.getName())) + return false; + + if (OptimizedMarshalAware.class.isAssignableFrom(cls)) + return true; + + try { + OptimizedClassDescriptor desc = OptimizedMarshallerUtils.classDescriptor(clsMap, cls, ctx, mapper); + + if (desc.fields() != null && desc.fields().fieldsIndexingSupported()) { + //The function is called on kernel startup, calling metaHandler.metadata() will hang the grid, + //because the underlying cache is not ready. + //if (metaHandler.metadata(desc.typeId()) != null) + // return true; + + OptimizedObjectMetadata meta = new OptimizedObjectMetadata(); + + for (ClassFields clsFields : desc.fields().fieldsList()) + for (FieldInfo info : clsFields.fieldInfoList()) + meta.addMeta(info.id(), info.type()); + + metaHandler.addMeta(desc.typeId(), meta); + + return true; + } + } + catch (IOException e) { + throw new IgniteCheckedException("Failed to put meta for class: " + cls.getName(), e); + } + + return false; + } + + /** + * Checks whether fields indexing is enabled for objects of the given {@code cls}. + * + * @param cls Class. + * @return {@code true} if fields indexing is enabled. + */ + public boolean fieldsIndexingEnabled(Class<?> cls) { + assert metaHandler != null; + + if (ctx.isSystemType(cls.getName())) + return false; + + if (OptimizedMarshalAware.class.isAssignableFrom(cls)) + return true; + + try { + OptimizedClassDescriptor desc = OptimizedMarshallerUtils.classDescriptor(clsMap, cls, ctx, mapper); + + return desc.fields() != null && desc.fields().fieldsIndexingSupported() && + metaHandler.metadata(desc.typeId()) != null; + } + catch (IOException e) { + throw new IgniteException("Failed to load class description: " + cls); + } + } + + /** {@inheritDoc} */ + @Override public void setPoolSize(int poolSize) { + OptimizedObjectStreamExtRegistry.poolSize(poolSize); + } + + /** {@inheritDoc} */ + @Override public void marshal(@Nullable Object obj, OutputStream out) throws IgniteCheckedException { + assert out != null; + + OptimizedObjectOutputStreamExt objOut = null; + + try { + objOut = OptimizedObjectStreamExtRegistry.out(); + + objOut.context(clsMap, ctx, mapper, requireSer, metaHandler); + + objOut.out().outputStream(out); + + objOut.writeObject(obj); + } + catch (IOException e) { + throw new IgniteCheckedException("Failed to serialize object: " + obj, e); + } + finally { + OptimizedObjectStreamExtRegistry.closeOut(objOut); + } + } + + /** {@inheritDoc} */ + @Override public byte[] marshal(@Nullable Object obj) throws IgniteCheckedException { + OptimizedObjectOutputStreamExt objOut = null; + + try { + objOut = OptimizedObjectStreamExtRegistry.out(); + + objOut.context(clsMap, ctx, mapper, requireSer, metaHandler); + + objOut.writeObject(obj); + + return objOut.out().array(); + } + catch (IOException e) { + throw new IgniteCheckedException("Failed to serialize object: " + obj, e); + } + finally { + OptimizedObjectStreamExtRegistry.closeOut(objOut); + } + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override public <T> T unmarshal(InputStream in, @Nullable ClassLoader clsLdr) throws IgniteCheckedException { + assert in != null; + + OptimizedObjectInputStreamExt objIn = null; + + try { + objIn = OptimizedObjectStreamExtRegistry.in(); + + objIn.context(clsMap, ctx, mapper, clsLdr != null ? clsLdr : dfltClsLdr, metaHandler); + + objIn.in().inputStream(in); + + return (T)objIn.readObject(); + } + catch (IOException e) { + throw new IgniteCheckedException("Failed to deserialize object with given class loader: " + clsLdr, e); + } + catch (ClassNotFoundException e) { + throw new IgniteCheckedException("Failed to find class with given class loader for unmarshalling " + + "(make sure same versions of all classes are available on all nodes or " + + "enable peer-class-loading): " + clsLdr, e); + } + finally { + OptimizedObjectStreamExtRegistry.closeIn(objIn); + } + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override public <T> T unmarshal(byte[] arr, @Nullable ClassLoader clsLdr) throws IgniteCheckedException { + return unmarshal(arr, 0, arr.length, clsLdr); + } + + /** + * Unmarshals object from byte array using given class loader and offset with len. + * + * @param <T> Type of unmarshalled object. + * @param arr Byte array. + * @param off Object's offset in the array. + * @param len Object's length in the array. + * @param clsLdr Class loader to use. + * @return Unmarshalled object. + * @throws IgniteCheckedException If unmarshalling failed. + */ + public <T> T unmarshal(byte[] arr, int off, int len, @Nullable ClassLoader clsLdr) throws IgniteCheckedException { + assert arr != null; + + OptimizedObjectInputStreamExt objIn = null; + + try { + objIn = OptimizedObjectStreamExtRegistry.in(); + + objIn.context(clsMap, ctx, mapper, clsLdr != null ? clsLdr : dfltClsLdr, metaHandler); + + objIn.in().bytes(arr, off, len); + + return (T)objIn.readObject(); + } + catch (IOException e) { + throw new IgniteCheckedException("Failed to deserialize object with given class loader: " + clsLdr, e); + } + catch (ClassNotFoundException e) { + throw new IgniteCheckedException("Failed to find class with given class loader for unmarshalling " + + "(make sure same version of all classes are available on all nodes or" + + " enable peer-class-loading): " + clsLdr, e); + } + finally { + OptimizedObjectStreamExtRegistry.closeIn(objIn); + } + } + + /** + * Checks whether object, serialized to byte array {@code arr}, has a field with name {@code fieldName}. + * + * @param fieldName Field name. + * @param arr Object's serialized form. + * @param off Object's start off. + * @param len Object's len. + * @return {@code true} if field exists. + */ + public boolean hasField(String fieldName, byte[] arr, int off, int len) throws IgniteCheckedException { + assert arr != null && fieldName != null; + + OptimizedObjectInputStreamExt objIn = null; + + try { + objIn = OptimizedObjectStreamExtRegistry.in(); + + objIn.context(clsMap, ctx, mapper, dfltClsLdr, metaHandler); + + objIn.in().bytes(arr, off, len); + + return objIn.hasField(fieldName); + } + catch (IOException e) { + throw new IgniteCheckedException("Failed to find field with name: " + fieldName, e); + } + finally { + OptimizedObjectStreamExtRegistry.closeIn(objIn); + } + } + + /** + * Looks up field with the given name and returns it in one of the following representations. If the field is + * serializable and has a footer then it's not deserialized but rather returned wrapped by {@link CacheObjectImpl} + * for future processing. In all other cases the field is fully deserialized. + * + * @param fieldName Field name. + * @param arr Object's serialized form. + * @param off Object's start offset. + * @param len Object's len. + * @param clsLdr Class loader. + * @param <T> Expected field class. + * @return Field. + * @throws IgniteCheckedException In case of error. + */ + public <T> T readField(String fieldName, byte[] arr, int off, int len, @Nullable ClassLoader clsLdr) + throws IgniteCheckedException { + + assert arr != null && fieldName != null; + + OptimizedObjectInputStreamExt objIn = null; + + try { + objIn = OptimizedObjectStreamExtRegistry.in(); + + objIn.context(clsMap, ctx, mapper, clsLdr != null ? clsLdr : dfltClsLdr, metaHandler); + + objIn.in().bytes(arr, off, len); + + return objIn.readField(fieldName); + } + catch (IOException e) { + throw new IgniteCheckedException("Failed to find field with name: " + fieldName, e); + } + catch (ClassNotFoundException e) { + throw new IgniteCheckedException("Failed to find class with given class loader for unmarshalling " + + "(make sure same version of all classes are available on all nodes or" + + " enable peer-class-loading): " + clsLdr, e); + } + finally { + OptimizedObjectStreamExtRegistry.closeIn(objIn); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5749b068/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerMetaHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerMetaHandler.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerMetaHandler.java new file mode 100644 index 0000000..5fad57c --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerMetaHandler.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.marshaller.optimized; + +/** + * Metadata handler for optimized objects. + */ +public interface OptimizedMarshallerMetaHandler { + /** + * Adds meta data. + * + * @param typeId Type ID. + * @param meta Meta data. + */ + void addMeta(int typeId, OptimizedObjectMetadata meta); + + + /** + * Gets meta data for provided type ID. + * + * @param typeId Type ID. + * @return Meta data. + */ + OptimizedObjectMetadata metadata(int typeId); +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5749b068/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerUtils.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerUtils.java index 7a7ee69..cd25f1c 100644 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerUtils.java @@ -144,6 +144,9 @@ public class OptimizedMarshallerUtils { /** */ public static final byte SERIALIZABLE = 102; + /** */ + public static final byte MARSHAL_AWARE = 103; + /** UTF-8 character name. */ static final Charset UTF_8 = Charset.forName("UTF-8"); http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5749b068/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStream.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStream.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStream.java index c8a85b2..6eeadc8 100644 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStream.java +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStream.java @@ -18,10 +18,12 @@ package org.apache.ignite.marshaller.optimized; import org.apache.ignite.*; +import org.apache.ignite.internal.processors.cache.*; import org.apache.ignite.internal.util.*; import org.apache.ignite.internal.util.io.*; import org.apache.ignite.internal.util.typedef.internal.*; import org.apache.ignite.marshaller.*; +import org.jetbrains.annotations.*; import sun.misc.*; import java.io.*; @@ -30,11 +32,12 @@ import java.util.*; import java.util.concurrent.*; import static org.apache.ignite.marshaller.optimized.OptimizedMarshallerUtils.*; +import static org.apache.ignite.marshaller.optimized.OptimizedMarshallerExt.*; /** * Optimized object input stream. */ -public class OptimizedObjectInputStream extends ObjectInputStream { +public class OptimizedObjectInputStream extends ObjectInputStream implements OptimizedFieldsReader { /** Unsafe. */ private static final Unsafe UNSAFE = GridUnsafe.unsafe(); @@ -51,6 +54,9 @@ public class OptimizedObjectInputStream extends ObjectInputStream { protected ClassLoader clsLdr; /** */ + protected OptimizedMarshallerMetaHandler metaHandler; + + /** */ protected GridDataInput in; /** */ @@ -95,6 +101,25 @@ public class OptimizedObjectInputStream extends ObjectInputStream { } /** + * @param clsMap Class descriptors by class map. + * @param ctx Context. + * @param mapper ID mapper. + * @param clsLdr Class loader. + * @param metaHandler Metadata handler. + */ + protected void context( + ConcurrentMap<Class, OptimizedClassDescriptor> clsMap, + MarshallerContext ctx, + OptimizedMarshallerIdMapper mapper, + ClassLoader clsLdr, + OptimizedMarshallerMetaHandler metaHandler) + { + context(clsMap, ctx, mapper, clsLdr); + + this.metaHandler = metaHandler; + } + + /** * @return Input. */ public GridDataInput in() { @@ -115,6 +140,7 @@ public class OptimizedObjectInputStream extends ObjectInputStream { ctx = null; clsLdr = null; clsMap = null; + metaHandler = null; } /** {@inheritDoc} */ @@ -241,6 +267,7 @@ public class OptimizedObjectInputStream extends ObjectInputStream { case ENUM: case EXTERNALIZABLE: case SERIALIZABLE: + case MARSHAL_AWARE: int typeId = readInt(); OptimizedClassDescriptor desc = typeId == 0 ? @@ -481,6 +508,46 @@ public class OptimizedObjectInputStream extends ObjectInputStream { } /** + * Reads {@link OptimizedMarshalAware} object. + * + * @param constructor Constructor. + * @param readResolveMtd {@code readResolve} method. + * @return Object. + * @throws ClassNotFoundException If class not found. + * @throws IOException In case of error. + */ + Object readMarshalAware(Constructor<?> constructor, Method readResolveMtd) + throws ClassNotFoundException, IOException { + Object obj; + + try { + obj = constructor.newInstance(); + } + catch (InstantiationException | InvocationTargetException | IllegalAccessException e) { + throw new IOException(e); + } + + int handle = handles.assign(obj); + + OptimizedMarshalAware extObj = ((OptimizedMarshalAware)obj); + + extObj.readFields(this); + + if (readResolveMtd != null) { + try { + obj = readResolveMtd.invoke(obj); + + handles.set(handle, obj); + } + catch (IllegalAccessException | InvocationTargetException e) { + throw new IOException(e); + } + } + + return obj; + } + + /** * Reads serializable object. * * @param cls Class. @@ -935,6 +1002,126 @@ public class OptimizedObjectInputStream extends ObjectInputStream { return new GetFieldImpl(this); } + /** {@inheritDoc} */ + @Override public byte readByte(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Override public short readShort(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Override public int readInt(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Override public long readLong(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Override public float readFloat(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Override public double readDouble(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Override public char readChar(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Override public boolean readBoolean(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Nullable @Override public String readString(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Nullable @Override public <T> T readObject(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Nullable @Override public byte[] readByteArray(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Nullable @Override public short[] readShortArray(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Nullable @Override public int[] readIntArray(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Nullable @Override public long[] readLongArray(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Nullable @Override public float[] readFloatArray(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Nullable @Override public double[] readDoubleArray(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Nullable @Override public char[] readCharArray(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Nullable @Override public boolean[] readBooleanArray(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Nullable @Override public String[] readStringArray(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Nullable @Override public Object[] readObjectArray(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Nullable @Override public <T> Collection<T> readCollection(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Nullable @Override public <K, V> Map<K, V> readMap(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Nullable @Override public <T extends Enum<?>> T readEnum(String fieldName) throws IOException { + return doReadField(fieldName); + } + + /** {@inheritDoc} */ + @Nullable @Override public <T extends Enum<?>> T[] readEnumArray(String fieldName) throws IOException { + return doReadField(fieldName); + } + /** * Skips object footer from the underlying stream. * @@ -955,6 +1142,209 @@ public class OptimizedObjectInputStream extends ObjectInputStream { return 0; } + /** + * Checks whether the object has a field with name {@code fieldName}. + * + * @param fieldName Field name. + * @return {@code true} if field exists, {@code false} otherwise. + * @throws IOException in case of error. + */ + public boolean hasField(String fieldName) throws IOException { + int pos = in.position(); + + byte type = in.readByte(); + + if (type != SERIALIZABLE && type != MARSHAL_AWARE) { + in.position(pos); + return false; + } + + FieldRange range = fieldRange(fieldName, pos); + + in.position(pos); + + return range != null && range.start > 0; + } + + /** + * Looks up field with the given name and returns it in one of the following representations. If the field is + * serializable and has a footer then it's not deserialized but rather returned wrapped by {@link CacheObjectImpl} + * for future processing. In all other cases the field is fully deserialized. + * + * @param fieldName Field name. + * @return Field. + * @throws IOException In case of error. + * @throws ClassNotFoundException In case of error. + */ + public <F> F readField(String fieldName) throws IOException, ClassNotFoundException { + return doReadField(fieldName, false); + } + + /** + * Reads the field using footer. + * + * @param fieldName Field name. + * @param deserialize Deserialize field if it supports footer. + * @param <F> Field type. + * @return Field. + */ + private <F> F doReadField(String fieldName, boolean deserialize) throws IOException, ClassNotFoundException { + int pos = in.position(); + + byte type = in.readByte(); + + if (type != SERIALIZABLE && type != MARSHAL_AWARE) { + in.position(pos); + return null; + } + + FieldRange range = fieldRange(fieldName, pos); + + F field = null; + + if (range != null && range.start >= 0) { + in.position(range.start); + + if (deserialize) + field = (F)readObject(); + else { + byte fieldType = in.readByte(); + + if ((fieldType == SERIALIZABLE && metaHandler.metadata(in.readInt()) != null) || + fieldType == MARSHAL_AWARE) + //Do we need to make a copy of array? + field = (F)new CacheIndexedObjectImpl(in.array(), range.start, range.len); + else { + in.position(range.start); + field = (F)readObject(); + } + } + } + + in.position(pos); + + return field; + } + + /** + * Reads the field and deserializes it. + * + * @param fieldName Field name. + * @param <F> Field type. + * @return Field. + * @throws IOException In case of error. + */ + private <F> F doReadField(String fieldName) throws IOException { + try { + return doReadField(fieldName, true); + } + catch (ClassNotFoundException e) { + throw new IOException("Failed to read the field, class definition has not" + + " been found [field=" + fieldName + "]"); + } + } + + /** + * Returns field offset in the byte stream. + * + * @param fieldName Field name. + * @param start Object's start offset. + * @return positive range or {@code null} if the object doesn't have such a field. + * @throws IOException in case of error. + */ + private FieldRange fieldRange(String fieldName, int start) throws IOException { + int fieldId = resolveFieldId(fieldName); + + int typeId = readInt(); + + int clsNameLen = 0; + + if (typeId == 0) { + int pos = in.position(); + + typeId = OptimizedMarshallerUtils.resolveTypeId(readUTF(), mapper); + + clsNameLen = in.position() - pos; + } + + OptimizedObjectMetadata meta = metaHandler.metadata(typeId); + + if (meta == null) + // TODO: IGNITE-950 add warning! + return null; + + int end = in.size(); + + in.position(end - FOOTER_LEN_OFF); + + short footerLen = in.readShort(); + + if (footerLen == EMPTY_FOOTER) + return null; + + // +2 - skipping length at the beginning + int footerOff = (end - footerLen) + 2; + in.position(footerOff); + + int fieldOff = 0; + + for (OptimizedObjectMetadata.FieldInfo info : meta.getMeta()) { + int len; + boolean isHandle; + + if (info.length() == VARIABLE_LEN) { + int fieldInfo = in.readInt(); + + len = fieldInfo & FOOTER_BODY_LEN_MASK; + isHandle = ((fieldInfo & FOOTER_BODY_IS_HANDLE_MASK) >> FOOTER_BODY_HANDLE_MASK_BIT) == 1; + } + else { + len = info.length(); + isHandle = false; + } + + if (info.id() == fieldId) { + if (!isHandle) { + //object header len: 1 - for type, 4 - for type ID, 2 - for checksum. + fieldOff += 1 + 4 + clsNameLen + 2; + + return new FieldRange(start + fieldOff, len); + } + else + return new FieldRange(in.readInt(), in.readInt()); + } + else { + fieldOff += len; + + if (isHandle) { + in.skipBytes(8); + fieldOff += 8; + } + } + } + + return null; + } + + /** + * + */ + private static class FieldRange { + /** */ + private int start; + + /** */ + private int len; + + /** + * @param start Start. + * @param len Length. + */ + public FieldRange(int start, int len) { + this.start = start; + this.len = len; + } + } /** {@inheritDoc} */ @Override public void registerValidation(ObjectInputValidation obj, int pri) { // No-op. http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5749b068/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStreamExt.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStreamExt.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStreamExt.java new file mode 100644 index 0000000..34ca279 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStreamExt.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ignite.marshaller.optimized; + +import org.apache.ignite.internal.util.io.*; + +import java.io.*; + +import static org.apache.ignite.marshaller.optimized.OptimizedMarshallerUtils.*; +import static org.apache.ignite.marshaller.optimized.OptimizedMarshallerExt.*; + + +/** + * TODO: IGNITE-950 + */ +public class OptimizedObjectInputStreamExt extends OptimizedObjectInputStream { + /** {@inheritDoc} */ + public OptimizedObjectInputStreamExt(GridDataInput in) throws IOException { + super(in); + } + + /** {@inheritDoc} */ + @Override protected void skipFooter(Class<?> cls) throws IOException { + if (!ctx.isSystemType(cls.getName()) && metaHandler != null && + metaHandler.metadata(resolveTypeId(cls.getName(), mapper)) != null) { + short footerLen = in.readShort(); + + if (footerLen != EMPTY_FOOTER) + in.skipBytes(footerLen - 2); + } + } + + /** {@inheritDoc} */ + @Override protected int readFieldType() throws IOException { + return in.readByte(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5749b068/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadata.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadata.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadata.java new file mode 100644 index 0000000..9a5463b --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadata.java @@ -0,0 +1,172 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.marshaller.optimized; + +import org.apache.ignite.*; + +import java.io.*; +import java.util.*; + +/** + * Metadata that keeps fields information. Used in conjunction with the footer that is added to some objects during + * marshalling. + */ +public class OptimizedObjectMetadata implements Externalizable { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private List<FieldInfo> fieldsInfo; + + /** Constructor. */ + public OptimizedObjectMetadata() { + // No-op + } + + /** + * Adds meta for a new field. + * + * @param fieldId Field ID. + * @param fieldType Field type. + */ + public void addMeta(int fieldId, OptimizedFieldType fieldType) { + if (fieldsInfo == null) + fieldsInfo = new ArrayList<>(); + + + + fieldsInfo.add(new FieldInfo(fieldId, fieldType)); + } + + /** + * Gets {@link OptimizedObjectMetadata.FieldInfo} at the {@code index}. + * + * @param index Position. + * @return Field meta info. + */ + public FieldInfo getMeta(int index) { + return fieldsInfo.get(index); + } + /** + * Returns all the metadata stored for the object. + * + * @return Metadata collection. + */ + public List<FieldInfo> getMeta() { + return Collections.unmodifiableList(fieldsInfo); + } + + /** {@inheritDoc} */ + @Override public void writeExternal(ObjectOutput out) throws IOException { + if (fieldsInfo == null) { + out.writeInt(0); + return; + } + + out.writeInt(fieldsInfo.size()); + + for (FieldInfo fieldInfo : fieldsInfo) { + out.writeInt(fieldInfo.id); + out.writeByte(fieldInfo.type.ordinal()); + } + } + + /** {@inheritDoc} */ + @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + int size = in.readInt(); + + fieldsInfo = new ArrayList<>(size); + + for (int i = 0; i < size; i++) + fieldsInfo.add(new FieldInfo(in.readInt(), OptimizedFieldType.values()[in.readByte()])); + } + + /** + * Field info. + */ + public static class FieldInfo { + /** Field ID. */ + int id; + + /** Field len. */ + int len; + + /** Field type. */ + OptimizedFieldType type; + + /** + * Constructor. + * + * @param id Field ID. + * @param type Field len. + */ + public FieldInfo(int id, OptimizedFieldType type) { + this.id = id; + this.type = type; + + len = 1; + + switch (type) { + case BYTE: + case BOOLEAN: + len += 1; + break; + + case SHORT: + case CHAR: + len += 2; + break; + + case INT: + case FLOAT: + len += 4; + break; + + case LONG: + case DOUBLE: + len += 8; + break; + + case OTHER: + len = OptimizedMarshallerExt.VARIABLE_LEN; + break; + + default: + throw new IgniteException("Unknown field type: " + type); + } + + assert len != 1; + } + + /** + * Returns ID. + * @return ID. + */ + public int id() { + return id; + } + + /** + * Returns length. + * @return Lenght. + */ + public int length() { + return len; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5749b068/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadataKey.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadataKey.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadataKey.java new file mode 100644 index 0000000..ee85754 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadataKey.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.marshaller.optimized; + +import org.apache.ignite.internal.processors.cache.*; + +import java.io.*; + +/** + * Optimized object metadata key. + */ +public class OptimizedObjectMetadataKey extends GridCacheUtilityKey<OptimizedObjectMetadataKey> + implements Externalizable { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private int typeId; + + /** + * For {@link Externalizable}. + */ + public OptimizedObjectMetadataKey() { + // No-op + } + + /** + * Constructor. + * + * @param typeId Type id. + */ + public OptimizedObjectMetadataKey(int typeId) { + this.typeId = typeId; + } + + /** {@inheritDoc} */ + @Override public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(typeId); + } + + /** {@inheritDoc} */ + @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + typeId = in.readInt(); + } + + /** {@inheritDoc} */ + @Override protected boolean equalsx(OptimizedObjectMetadataKey key) { + return typeId == key.typeId; + } + + /** {@inheritDoc} */ + @Override public int hashCode() { + return typeId; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5749b068/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStream.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStream.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStream.java index 84b8351..1702b11 100644 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStream.java +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStream.java @@ -23,10 +23,12 @@ import org.apache.ignite.internal.util.io.*; import org.apache.ignite.internal.util.typedef.*; import org.apache.ignite.lang.*; import org.apache.ignite.marshaller.*; +import org.jetbrains.annotations.*; import java.io.*; import java.lang.reflect.*; import java.util.*; +import java.util.Date; import java.util.concurrent.*; import static org.apache.ignite.marshaller.optimized.OptimizedMarshallerUtils.*; @@ -34,7 +36,7 @@ import static org.apache.ignite.marshaller.optimized.OptimizedMarshallerUtils.*; /** * Optimized object output stream. */ -public class OptimizedObjectOutputStream extends ObjectOutputStream { +public class OptimizedObjectOutputStream extends ObjectOutputStream implements OptimizedFieldsWriter { /** */ private static final Collection<String> CONVERTED_ERR = F.asList( "weblogic/management/ManagementException", @@ -55,6 +57,9 @@ public class OptimizedObjectOutputStream extends ObjectOutputStream { protected ConcurrentMap<Class, OptimizedClassDescriptor> clsMap; /** */ + protected OptimizedMarshallerMetaHandler metaHandler; + + /** */ protected boolean requireSer; /** */ @@ -72,6 +77,9 @@ public class OptimizedObjectOutputStream extends ObjectOutputStream { /** */ private PutFieldImpl curPut; + /** */ + private Stack<Footer> marshalAwareFooters; + /** * @param out Output. * @throws IOException In case of error. @@ -97,6 +105,23 @@ public class OptimizedObjectOutputStream extends ObjectOutputStream { } /** + * @param clsMap Class descriptors by class map. + * @param ctx Context. + * @param mapper ID mapper. + * @param requireSer Require {@link Serializable} flag. + * @param metaHandler Metadata handler. + */ + protected void context(ConcurrentMap<Class, OptimizedClassDescriptor> clsMap, + MarshallerContext ctx, + OptimizedMarshallerIdMapper mapper, + boolean requireSer, + OptimizedMarshallerMetaHandler metaHandler) { + context(clsMap, ctx, mapper, requireSer); + + this.metaHandler = metaHandler; + } + + /** * @return Require {@link Serializable} flag. */ boolean requireSerializable() { @@ -116,6 +141,7 @@ public class OptimizedObjectOutputStream extends ObjectOutputStream { ctx = null; clsMap = null; + metaHandler = null; } /** {@inheritDoc} */ @@ -308,6 +334,36 @@ public class OptimizedObjectOutputStream extends ObjectOutputStream { } /** + * Writes marshal aware object with footer injected to the end of the stream. + * + * @param obj Object. + * @throws IOException In case of error. + */ + void writeMarshalAware(Object obj) throws IOException { + Footer footer = createFooter(obj.getClass()); + + if (footer == null) + throw new IOException("Failed to marshal OptimizedMarshalAware object. OptimizedMarshallerExt must be " + + "set to IgniteConfiguration [obj=" + obj.getClass().getName() + "]"); + + if (marshalAwareFooters == null) + marshalAwareFooters = new Stack<>(); + + marshalAwareFooters.push(footer); + + OptimizedMarshalAware marshalAwareObj = (OptimizedMarshalAware)obj; + + marshalAwareObj.writeFields(this); + + footer.write(); + + marshalAwareFooters.pop(); + + if (marshalAwareFooters.empty()) + marshalAwareFooters = null; + } + + /** * Writes serializable object. * * @param obj Object. @@ -840,6 +896,7 @@ public class OptimizedObjectOutputStream extends ObjectOutputStream { curObj = null; curFields = null; curPut = null; + marshalAwareFooters = null; } /** {@inheritDoc} */ @@ -862,6 +919,156 @@ public class OptimizedObjectOutputStream extends ObjectOutputStream { // No-op } + /** {@inheritDoc} */ + @Override public void writeByte(String fieldName, byte val) throws IOException { + writeFieldType(BYTE); + out.writeByte(val); + putFieldToFooter(fieldName, OptimizedFieldType.BYTE, 1); + } + + /** {@inheritDoc} */ + @Override public void writeShort(String fieldName, short val) throws IOException { + writeFieldType(SHORT); + out.writeShort(val); + putFieldToFooter(fieldName, OptimizedFieldType.SHORT, 2); + } + + /** {@inheritDoc} */ + @Override public void writeInt(String fieldName, int val) throws IOException { + writeFieldType(INT); + out.writeInt(val); + putFieldToFooter(fieldName, OptimizedFieldType.INT, 4); + } + + /** {@inheritDoc} */ + @Override public void writeLong(String fieldName, long val) throws IOException { + writeFieldType(LONG); + out.writeLong(val); + putFieldToFooter(fieldName, OptimizedFieldType.LONG, 8); + } + + /** {@inheritDoc} */ + @Override public void writeFloat(String fieldName, float val) throws IOException { + writeFieldType(FLOAT); + out.writeFloat(val); + putFieldToFooter(fieldName, OptimizedFieldType.FLOAT, 4); + } + + /** {@inheritDoc} */ + @Override public void writeDouble(String fieldName, double val) throws IOException { + writeFieldType(DOUBLE); + out.writeDouble(val); + putFieldToFooter(fieldName, OptimizedFieldType.DOUBLE, 8); + } + + /** {@inheritDoc} */ + @Override public void writeChar(String fieldName, char val) throws IOException { + writeFieldType(CHAR); + out.writeChar(val); + putFieldToFooter(fieldName, OptimizedFieldType.CHAR, 2); + } + + /** {@inheritDoc} */ + @Override public void writeBoolean(String fieldName, boolean val) throws IOException { + writeFieldType(BOOLEAN); + out.writeBoolean(val); + putFieldToFooter(fieldName, OptimizedFieldType.BOOLEAN, 1); + } + + /** {@inheritDoc} */ + @Override public void writeString(String fieldName, @Nullable String val) throws IOException { + writeObject(fieldName, val); + } + + /** {@inheritDoc} */ + @Override public void writeObject(String fieldName, @Nullable Object obj) throws IOException { + int pos = out.offset(); + + writeObject(obj); + putFieldToFooter(fieldName, OptimizedFieldType.OTHER, out.offset() - pos); + } + + /** {@inheritDoc} */ + @Override public void writeByteArray(String fieldName, @Nullable byte[] val) throws IOException { + writeObject(fieldName, val); + } + + /** {@inheritDoc} */ + @Override public void writeShortArray(String fieldName, @Nullable short[] val) throws IOException { + writeObject(fieldName, val); + } + + /** {@inheritDoc} */ + @Override public void writeIntArray(String fieldName, @Nullable int[] val) throws IOException { + writeObject(fieldName, val); + } + + /** {@inheritDoc} */ + @Override public void writeLongArray(String fieldName, @Nullable long[] val) throws IOException { + writeObject(fieldName, val); + } + + /** {@inheritDoc} */ + @Override public void writeFloatArray(String fieldName, @Nullable float[] val) throws IOException { + writeObject(fieldName, val); + } + + /** {@inheritDoc} */ + @Override public void writeDoubleArray(String fieldName, @Nullable double[] val) throws IOException { + writeObject(fieldName, val); + } + + /** {@inheritDoc} */ + @Override public void writeCharArray(String fieldName, @Nullable char[] val) throws IOException { + writeObject(fieldName, val); + } + + /** {@inheritDoc} */ + @Override public void writeBooleanArray(String fieldName, @Nullable boolean[] val) throws IOException { + writeObject(fieldName, val); + } + + /** {@inheritDoc} */ + @Override public void writeStringArray(String fieldName, @Nullable String[] val) throws IOException { + writeObject(fieldName, val); + } + + /** {@inheritDoc} */ + @Override public void writeObjectArray(String fieldName, @Nullable Object[] val) throws IOException { + writeObject(fieldName, val); + } + + /** {@inheritDoc} */ + @Override public <T> void writeCollection(String fieldName, @Nullable Collection<T> col) throws IOException { + writeObject(fieldName, col); + } + + /** {@inheritDoc} */ + @Override public <K, V> void writeMap(String fieldName, @Nullable Map<K, V> map) throws IOException { + writeObject(fieldName, map); + } + + /** {@inheritDoc} */ + @Override public <T extends Enum<?>> void writeEnum(String fieldName, T val) throws IOException { + writeObject(fieldName, val); + } + + /** {@inheritDoc} */ + @Override public <T extends Enum<?>> void writeEnumArray(String fieldName, T[] val) throws IOException { + writeObject(fieldName, val); + } + + /** + * Puts field to the footer. + * + * @param fieldName Field name. + * @param type Field type. + * @param len Field length. + */ + private void putFieldToFooter(String fieldName, OptimizedFieldType type, int len) { + marshalAwareFooters.peek().put(OptimizedMarshallerUtils.resolveFieldId(fieldName), type, len); + } + /** * Creates new instance of {@code Footer}. *