diff --git a/modules/binary/api/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java b/modules/binary/api/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java index d5e08498535bd..3b698f40a2669 100644 --- a/modules/binary/api/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java +++ b/modules/binary/api/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java @@ -25,6 +25,7 @@ import java.sql.Time; import java.sql.Timestamp; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -79,6 +80,21 @@ /** * Binary context. + * + *

Class loaders

+ * Binary code deals with exactly two kinds of class loaders: + * + * A {@code null} loader anywhere in the binary API means "use the default loader". + * Use {@link #resolveClassLoader(ClassLoader)} to turn a caller supplied loader into the one to actually use and + * {@link #isCustomLoader(ClassLoader)} to decide whether caching must be bypassed. */ public class BinaryContext { /** */ @@ -122,8 +138,8 @@ public class BinaryContext { /** Node name. */ private final @Nullable String igniteInstanceName; - /** Class loader. */ - private final @Nullable ClassLoader clsLdr; + /** Default class loader. Configured loader or the loader Ignite was loaded by. Never {@code null}. */ + private final ClassLoader clsLdr; /** Actual marshaller. */ private final BinaryMarshaller marsh; @@ -156,7 +172,7 @@ public class BinaryContext { * @param metaHnd Meta data handler. * @param marsh Binary marshaller. * @param igniteInstanceName Ignite instance name. - * @param clsLdr Class loader. + * @param clsLdr Configured class loader or {@code null} to use the loader Ignite was loaded by. * @param dfltSerializer Binary serializer. * @param idMapper Binary id mapper. * @param nameMapper Binary name mapper. @@ -185,7 +201,7 @@ public BinaryContext( this.metaHnd = metaHnd; this.igniteInstanceName = igniteInstanceName; - this.clsLdr = clsLdr; + this.clsLdr = clsLdr != null ? clsLdr : CommonUtils.gridClassLoader(); this.dfltSerializer = dfltSerializer; if (idMapper != null || nameMapper != null || !F.isEmpty(typeCfgs)) @@ -325,12 +341,43 @@ public String igniteInstanceName() { } /** - * @return Class loader. + * @return Default class loader. Configured loader or the loader Ignite was loaded by. Never {@code null}. */ public ClassLoader classLoader() { return clsLdr; } + /** + * @param ldr Caller supplied class loader or {@code null}. + * @return {@code ldr} if it is a custom loader, default loader otherwise. + * @see #isCustomLoader(ClassLoader) + */ + public ClassLoader resolveClassLoader(@Nullable ClassLoader ldr) { + return isCustomLoader(ldr) ? ldr : clsLdr; + } + + /** + * @param ldr Caller supplied class loader or {@code null}. + * @return {@code True} if {@code ldr} is a custom (deployment or user supplied) loader, + * {@code false} if it is {@code null}, the default loader or the loader Ignite was loaded by. + */ + public boolean isCustomLoader(@Nullable ClassLoader ldr) { + return ldr != null && ldr != clsLdr && ldr != CommonUtils.gridClassLoader(); + } + + /** + * @param clsName Class name. + * @return Class loaded by {@link #classLoader()} or {@code null} if it is not available to it. + */ + @Nullable private Class loadClassOrNull(String clsName) { + try { + return clsLdr.loadClass(clsName); + } + catch (ClassNotFoundException | NoClassDefFoundError ignored) { + return null; + } + } + /** * @param globalNameMapper Name mapper. * @param globalIdMapper ID mapper. @@ -370,7 +417,7 @@ private void configure( String affField = affFields.remove(clsName0); if (affField == null) { - Class cls = ClassLoaderUtils.classForName(clsName0); + Class cls = loadClassOrNull(clsName0); if (cls != null) affField = affFldNameProvider.apply(cls); @@ -384,7 +431,7 @@ private void configure( String affField = affFields.remove(clsName); if (affField == null) { - Class cls = ClassLoaderUtils.classForName(clsName); + Class cls = loadClassOrNull(clsName); if (cls != null) affField = affFldNameProvider.apply(cls); @@ -459,20 +506,24 @@ public static BinaryNameMapper defaultNameMapper() { } /** + * Lists classes of the package visible on the classpath of {@link #classLoader()}. + * When a custom loader is configured, the classpath Ignite itself was loaded from is scanned as well. + * * @param pkgName Package name. * @return Class names. */ @SuppressWarnings("ConstantConditions") - private static Iterable classesInPackage(String pkgName) { + private Iterable classesInPackage(String pkgName) { assert pkgName != null; Collection clsNames = new ArrayList<>(); - ClassLoader ldr = CommonUtils.gridClassLoader(); - String pkgPath = pkgName.replaceAll("\\.", "/"); - URL[] urls = CommonUtils.classLoaderUrls(ldr); + Collection urls = new LinkedHashSet<>(Arrays.asList(CommonUtils.classLoaderUrls(clsLdr))); + + if (clsLdr != CommonUtils.gridClassLoader()) + urls.addAll(Arrays.asList(CommonUtils.classLoaderUrls(CommonUtils.gridClassLoader()))); for (URL url : urls) { String proto = url.getProtocol().toLowerCase(); @@ -703,14 +754,14 @@ private BinaryClassDescriptor systemClassDescriptor(Class cls, String clsName /** * @param userType User type or not. * @param typeId Type ID. - * @param ldr Class loader or {@code null} to use {@link CommonUtils#gridClassLoader()}. + * @param ldr Custom class loader or {@code null} to use {@link #classLoader()}. * @param registerMeta If {@code true}, then metadata will be registered along with the type descriptor. * @return Class descriptor. */ BinaryClassDescriptor descriptorForTypeId( boolean userType, int typeId, - ClassLoader ldr, + @Nullable ClassLoader ldr, boolean registerMeta ) { assert typeId != GridBinaryMarshaller.UNREGISTERED_TYPE_ID; @@ -721,6 +772,8 @@ BinaryClassDescriptor descriptorForTypeId( if (desc != null) return desc; + ldr = resolveClassLoader(ldr); + Class cls; try { @@ -749,8 +802,9 @@ BinaryClassDescriptor descriptorForTypeId( if (userType && ldr != null && !ldr.equals(CommonUtils.gridClassLoader()) - && (desc = descriptorForTypeId(true, typeId, null, registerMeta)) != null) + && (desc = descriptorForTypeId(true, typeId, null, registerMeta)) != null) { return desc; + } throw new BinaryInvalidTypeException(e); } @@ -759,8 +813,9 @@ BinaryClassDescriptor descriptorForTypeId( if (userType && ldr != null && !ldr.equals(CommonUtils.gridClassLoader()) - && (desc = descriptorForTypeId(true, typeId, null, registerMeta)) != null) + && (desc = descriptorForTypeId(true, typeId, null, registerMeta)) != null) { return desc; + } throw new BinaryObjectException("Failed resolve class for ID: " + typeId, e); } @@ -1115,14 +1170,7 @@ public void registerUserType(String clsName, @Nullable Map enumMap) throws BinaryObjectException { assert mapper != null; - Class cls = null; - - try { - cls = CommonUtils.resolveClassLoader(null, classLoader()).loadClass(clsName); - } - catch (ClassNotFoundException | NoClassDefFoundError ignored) { - // No-op. - } + Class cls = loadClassOrNull(clsName); String typeName = mapper.typeName(clsName); diff --git a/modules/binary/api/src/main/java/org/apache/ignite/internal/marshaller/ClassLoaderUtils.java b/modules/binary/api/src/main/java/org/apache/ignite/internal/marshaller/ClassLoaderUtils.java index 10c8f697e2862..00ccbf9e5d6f5 100644 --- a/modules/binary/api/src/main/java/org/apache/ignite/internal/marshaller/ClassLoaderUtils.java +++ b/modules/binary/api/src/main/java/org/apache/ignite/internal/marshaller/ClassLoaderUtils.java @@ -29,6 +29,12 @@ /** * Utility class to deal with class loading. * Contains internal class cache. + *

+ * A {@code null} class loader passed to any method of this class means the loader Ignite itself was loaded by, + * {@link CommonUtils#gridClassLoader()}. This fallback serves {@link org.apache.ignite.marshaller.Marshaller} API + * callers and deployment code. + * Binary code resolves loaders through {@code BinaryContext#resolveClassLoader(ClassLoader)} and never passes + * {@code null} here. */ public class ClassLoaderUtils { /** Primitive class map. */ diff --git a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryArray.java b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryArray.java index 6fd7ef9bff346..62b8de21afc72 100644 --- a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryArray.java +++ b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryArray.java @@ -104,7 +104,7 @@ public BinaryArray(BinaryContext ctx, int compTypeId, @Nullable String compClsNa /** {@inheritDoc} */ @Override public T deserialize(ClassLoader ldr) throws BinaryObjectException { - if (ldr != null) + if (ctx.isCustomLoader(ldr)) Marshallers.USE_CACHE.set(Boolean.FALSE); try { diff --git a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java index 4242ac535fe61..2f3ea279920b9 100644 --- a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java +++ b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java @@ -169,13 +169,15 @@ public BinaryEnumObjectImpl(BinaryContext ctx, byte[] arr) { /** {@inheritDoc} */ @Override public T deserialize(@Nullable ClassLoader ldr) throws BinaryObjectException { - if (ldr != null) + boolean customLdr = ctx.isCustomLoader(ldr); + + if (customLdr) Marshallers.USE_CACHE.set(Boolean.FALSE); try { Class cls = BinaryImplUtils.resolveClass(ctx, typeId, clsName, ldr, false); - return (T)(ldr == null ? BinaryEnumCache.get(cls, ord) : uncachedValue(cls)); + return (T)(customLdr ? uncachedValue(cls) : BinaryEnumCache.get(cls, ord)); } finally { Marshallers.USE_CACHE.set(Boolean.TRUE); diff --git a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryImplUtils.java b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryImplUtils.java index 0ca035ef9b78e..59a29bafdc0c5 100644 --- a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryImplUtils.java +++ b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryImplUtils.java @@ -17,13 +17,11 @@ package org.apache.ignite.internal.binary; import java.io.ByteArrayInputStream; - import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.binary.BinaryInvalidTypeException; import org.apache.ignite.binary.BinaryObjectException; import org.apache.ignite.internal.binary.streams.BinaryInputStream; import org.apache.ignite.internal.marshaller.ClassLoaderUtils; -import org.apache.ignite.internal.util.CommonUtils; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.lang.IgniteBiTuple; import org.jetbrains.annotations.Nullable; @@ -362,6 +360,9 @@ static String doReadClassName(BinaryInputStream in) { /** * Read object serialized using optimized marshaller. * + * @param in Input stream. + * @param ctx Binary context. + * @param clsLdr Custom class loader or {@code null} to use {@link BinaryContext#classLoader()}. * @return Result. */ public static Object doReadOptimized(BinaryInputStream in, BinaryContext ctx, @Nullable ClassLoader clsLdr) { @@ -370,7 +371,7 @@ public static Object doReadOptimized(BinaryInputStream in, BinaryContext ctx, @N ByteArrayInputStream input = new ByteArrayInputStream(in.array(), in.position(), len); try { - return ctx.optimizedMarsh().unmarshal(input, CommonUtils.resolveClassLoader(clsLdr, ctx.classLoader())); + return ctx.optimizedMarsh().unmarshal(input, ctx.resolveClassLoader(clsLdr)); } catch (IgniteCheckedException e) { throw new BinaryObjectException("Failed to unmarshal object with optimized marshaller", e); @@ -394,8 +395,7 @@ static Class resolveClass(BinaryContext ctx, int typeId, @Nullable String clsNam @Nullable ClassLoader ldr, boolean registerMeta) { Class cls; - if (ldr == null) - ldr = ctx.classLoader(); + ldr = ctx.resolveClassLoader(ldr); if (typeId != GridBinaryMarshaller.UNREGISTERED_TYPE_ID) cls = ctx.descriptorForTypeId(true, typeId, ldr, registerMeta).describedClass(); diff --git a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java index a0bac1118da80..65bf49609c9f6 100644 --- a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java +++ b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java @@ -701,7 +701,7 @@ else if (fieldOffsetLen == BinaryImplUtils.OFFSET_2) /** {@inheritDoc} */ @Nullable @Override public T deserialize(@Nullable ClassLoader ldr) throws BinaryObjectException { - if (ldr == null) + if (!ctx.isCustomLoader(ldr)) return deserialize(); Marshallers.USE_CACHE.set(Boolean.FALSE); diff --git a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryObjectOffheapImpl.java b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryObjectOffheapImpl.java index 3f21909780a31..320124813f812 100644 --- a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryObjectOffheapImpl.java +++ b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryObjectOffheapImpl.java @@ -400,7 +400,7 @@ else if (fieldOffLen == BinaryImplUtils.OFFSET_2) /** {@inheritDoc} */ @Nullable @Override public T deserialize(@Nullable ClassLoader ldr) throws BinaryObjectException { - if (ldr == null) + if (!ctx.isCustomLoader(ldr)) return deserialize(); Marshallers.USE_CACHE.set(Boolean.FALSE); diff --git a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java index 9fd4ba5c57280..2eb4b53795a38 100644 --- a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java +++ b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java @@ -110,7 +110,10 @@ public final class BinaryReaderExImpl extends BinaryReaderHandlesHolder implemen /** Input stream. */ private final BinaryInputStream in; - /** Class loaded. */ + /** + * Class loader to resolve classes with: custom loader or {@link BinaryContext#classLoader()}, resolved once here. + * {@code null} only when {@link #ctx} is {@code null}; such readers can read primitives only. + */ private final ClassLoader ldr; /** */ @@ -204,23 +207,22 @@ public BinaryReaderExImpl(BinaryContext ctx, * * @param ctx Context. * @param in Input stream. - * @param ldr Class loader. - * @param hnds Context. + * @param ldr Custom class loader or {@code null} to use {@link BinaryContext#classLoader()}. + * @param hnds Reader handles or {@code null} to start a new handles context. * @param skipHdrCheck Whether to skip header check. * @param forUnmarshal {@code True} if reader is need to unmarshal object. */ public BinaryReaderExImpl(BinaryContext ctx, BinaryInputStream in, - ClassLoader ldr, + @Nullable ClassLoader ldr, @Nullable BinaryReaderHandles hnds, boolean skipHdrCheck, boolean forUnmarshal) { - // Initialize base members. super(hnds); this.ctx = ctx; this.in = in; - this.ldr = ldr; + this.ldr = ctx == null ? ldr : ctx.resolveClassLoader(ldr); start = in.position(); @@ -1318,7 +1320,16 @@ float readFloat(int fieldId) throws BinaryObjectException { /** {@inheritDoc} */ @Nullable @Override public Object readObjectDetached(boolean deserialize) throws BinaryObjectException { - return unmarshal(in, ctx, ldr, new BinaryReaderHandlesHolder(null), true, deserialize); + BinaryReaderHandles prevHnds = hnds; + + hnds = null; + + try { + return unmarshal(in, ctx, ldr, this, true, deserialize); + } + finally { + hnds = prevHnds; + } } /** {@inheritDoc} */ @@ -2069,61 +2080,61 @@ public BinarySchema getOrCreateSchema() { return BinaryUtils.doReadString(in()); case GridBinaryMarshaller.DECIMAL: - return doReadDecimal(in()); + return doReadDecimal(in); case GridBinaryMarshaller.UUID: - return doReadUuid(in()); + return doReadUuid(in); case GridBinaryMarshaller.TIME: - return doReadTime(in()); + return doReadTime(in); case GridBinaryMarshaller.TIMESTAMP: - return doReadTimestamp(in()); + return doReadTimestamp(in); case GridBinaryMarshaller.DATE: - return doReadDate(in()); + return doReadDate(in); case GridBinaryMarshaller.BOOLEAN_ARR: - return doReadBooleanArray(in()); + return doReadBooleanArray(in); case GridBinaryMarshaller.BYTE_ARR: return BinaryUtils.doReadByteArray(in()); case GridBinaryMarshaller.CHAR_ARR: - return doReadCharArray(in()); + return doReadCharArray(in); case GridBinaryMarshaller.SHORT_ARR: - return doReadShortArray(in()); + return doReadShortArray(in); case GridBinaryMarshaller.INT_ARR: - return doReadIntArray(in()); + return doReadIntArray(in); case GridBinaryMarshaller.LONG_ARR: - return doReadLongArray(in()); + return doReadLongArray(in); case GridBinaryMarshaller.FLOAT_ARR: - return doReadFloatArray(in()); + return doReadFloatArray(in); case GridBinaryMarshaller.DOUBLE_ARR: - return doReadDoubleArray(in()); + return doReadDoubleArray(in); case GridBinaryMarshaller.STRING_ARR: return BinaryUtils.doReadStringArray(in()); case GridBinaryMarshaller.DECIMAL_ARR: - return doReadDecimalArray(in()); + return doReadDecimalArray(in); case GridBinaryMarshaller.UUID_ARR: - return doReadUuidArray(in()); + return doReadUuidArray(in); case GridBinaryMarshaller.TIME_ARR: - return doReadTimeArray(in()); + return doReadTimeArray(in); case GridBinaryMarshaller.TIMESTAMP_ARR: - return doReadTimestampArray(in()); + return doReadTimestampArray(in); case GridBinaryMarshaller.DATE_ARR: - return doReadDateArray(in()); + return doReadDateArray(in); default: in().position(in().position() - 1); @@ -2846,8 +2857,6 @@ protected Object readFixedType(BinaryFieldDescriptor fld) throws BinaryObjectExc /** * Read binary enum. * - * @param in Input stream. - * @param ctx Binary context. * @return Enum. */ private static BinaryObjectEx doReadBinaryEnum(BinaryInputStream in, BinaryContext ctx) { @@ -2947,6 +2956,7 @@ private enum Flag { } /** + * @param in Input stream. * @return Value. */ private static boolean[] doReadBooleanArray(BinaryInputStream in) { @@ -2956,6 +2966,7 @@ private static boolean[] doReadBooleanArray(BinaryInputStream in) { } /** + * @param in Input stream. * @return Value. */ private static short[] doReadShortArray(BinaryInputStream in) { @@ -2965,6 +2976,7 @@ private static short[] doReadShortArray(BinaryInputStream in) { } /** + * @param in Input stream. * @return Value. */ private static char[] doReadCharArray(BinaryInputStream in) { @@ -2974,6 +2986,7 @@ private static char[] doReadCharArray(BinaryInputStream in) { } /** + * @param in Input stream. * @return Value. */ private static int[] doReadIntArray(BinaryInputStream in) { @@ -2983,6 +2996,7 @@ private static int[] doReadIntArray(BinaryInputStream in) { } /** + * @param in Input stream. * @return Value. */ private static long[] doReadLongArray(BinaryInputStream in) { @@ -2992,6 +3006,7 @@ private static long[] doReadLongArray(BinaryInputStream in) { } /** + * @param in Input stream. * @return Value. */ private static float[] doReadFloatArray(BinaryInputStream in) { @@ -3001,6 +3016,7 @@ private static float[] doReadFloatArray(BinaryInputStream in) { } /** + * @param in Input stream. * @return Value. */ private static double[] doReadDoubleArray(BinaryInputStream in) { @@ -3010,6 +3026,7 @@ private static double[] doReadDoubleArray(BinaryInputStream in) { } /** + * @param in Input stream. * @return Value. */ private static BigDecimal doReadDecimal(BinaryInputStream in) { @@ -3030,6 +3047,7 @@ private static BigDecimal doReadDecimal(BinaryInputStream in) { } /** + * @param in Input stream. * @return Value. */ private static UUID doReadUuid(BinaryInputStream in) { @@ -3037,6 +3055,7 @@ private static UUID doReadUuid(BinaryInputStream in) { } /** + * @param in Input stream. * @return Value. */ private static Date doReadDate(BinaryInputStream in) { @@ -3046,6 +3065,7 @@ private static Date doReadDate(BinaryInputStream in) { } /** + * @param in Input stream. * @return Value. */ private static Timestamp doReadTimestamp(BinaryInputStream in) { @@ -3060,6 +3080,7 @@ private static Timestamp doReadTimestamp(BinaryInputStream in) { } /** + * @param in Input stream. * @return Value. */ private static Time doReadTime(BinaryInputStream in) { @@ -3069,6 +3090,7 @@ private static Time doReadTime(BinaryInputStream in) { } /** + * @param in Input stream. * @return Value. * @throws BinaryObjectException In case of error. */ @@ -3094,6 +3116,7 @@ private static BigDecimal[] doReadDecimalArray(BinaryInputStream in) throws Bina } /** + * @param in Input stream. * @return Value. * @throws BinaryObjectException In case of error. */ @@ -3119,6 +3142,7 @@ private static UUID[] doReadUuidArray(BinaryInputStream in) throws BinaryObjectE } /** + * @param in Input stream. * @return Value. * @throws BinaryObjectException In case of error. */ @@ -3144,6 +3168,7 @@ private static Date[] doReadDateArray(BinaryInputStream in) throws BinaryObjectE } /** + * @param in Input stream. * @return Value. * @throws BinaryObjectException In case of error. */ @@ -3169,6 +3194,7 @@ private static Timestamp[] doReadTimestampArray(BinaryInputStream in) throws Bin } /** + * @param in Input stream. * @return Value. * @throws BinaryObjectException In case of error. */ @@ -3194,6 +3220,8 @@ private static Time[] doReadTimeArray(BinaryInputStream in) throws BinaryObjectE } /** + * @param in Input stream. + * @param ctx Context. * @return Value. */ private static BinaryObject doReadBinaryObject(BinaryInputStream in, BinaryContext ctx, boolean detach) { @@ -3257,6 +3285,10 @@ private static Class doReadClass(BinaryInputStream in, BinaryContext ctx, ClassL } /** + * @param in Input stream. + * @param ctx Context. + * @param ldr Class loader. + * @param handles Handles holder. * @return Value. */ @SuppressWarnings("ConstantConditions") @@ -3269,7 +3301,7 @@ private static Object doReadProxy(BinaryInputStream in, BinaryContext ctx, Class InvocationHandler ih = (InvocationHandler)doReadObject(in, ctx, ldr, handles); - return Proxy.newProxyInstance(ldr != null ? ldr : CommonUtils.gridClassLoader(), intfs, ih); + return Proxy.newProxyInstance(ldr, intfs, ih); } /** @@ -3360,6 +3392,10 @@ private static Object[] doReadBinaryEnumArray(BinaryInputStream in, BinaryContex } /** + * @param in Input stream. + * @param ctx Context. + * @param ldr Class loader. + * @param handles Handles holder. * @return Object. * @throws BinaryObjectException In case of error. */ @@ -3369,15 +3405,24 @@ private static Object[] doReadBinaryEnumArray(BinaryInputStream in, BinaryContex } /** + * Unmarshals the value at the current stream position without deserialization of user types. + * + * @param in Input stream. + * @param ctx Context. + * @param ldr Custom class loader or {@code null} to use {@link BinaryContext#classLoader()}. * @return Unmarshalled value. * @throws BinaryObjectException In case of error. */ - @Nullable static Object unmarshal(BinaryInputStream in, BinaryContext ctx, ClassLoader ldr) + @Nullable static Object unmarshal(BinaryInputStream in, BinaryContext ctx, @Nullable ClassLoader ldr) throws BinaryObjectException { - return unmarshal(in, ctx, ldr, new BinaryReaderHandlesHolder(null)); + return unmarshal(in, ctx, ctx.resolveClassLoader(ldr), new BinaryReaderHandlesHolder(null), false, false); } /** + * @param in Input stream. + * @param ctx Context. + * @param ldr Resolved class loader. + * @param handles Handles holder. * @return Unmarshalled value. * @throws BinaryObjectException In case of error. */ @@ -3387,6 +3432,10 @@ private static Object[] doReadBinaryEnumArray(BinaryInputStream in, BinaryContex } /** + * @param in Input stream. + * @param ctx Context. + * @param ldr Class loader. + * @param handles Handles holder. * @return Unmarshalled value. * @throws BinaryObjectException In case of error. */ @@ -3646,6 +3695,10 @@ private static BinaryArray doReadBinaryArray(BinaryInputStream in, BinaryContext } /** + * @param in Input stream. + * @param ctx Context. + * @param ldr Class loader. + * @param handles Handles holder. * @param deserialize Deep flag. * @param factory Collection factory. * @return Value. @@ -3718,6 +3771,10 @@ private static Collection doReadCollection(BinaryInputStream in, BinaryContex } /** + * @param in Input stream. + * @param ctx Context. + * @param ldr Class loader. + * @param handles Handles holder. * @param deserialize Deep flag. * @param factory Map factory. * @return Value. @@ -3776,6 +3833,10 @@ private static Collection doReadCollection(BinaryInputStream in, BinaryContex /** * Deserialize or unmarshal the object. * + * @param in Input stream. + * @param ctx Context. + * @param ldr Class loader. + * @param handles Handles holder. * @param deserialize Deserialize. * @return Result. */ @@ -3787,6 +3848,7 @@ private static Object deserializeOrUnmarshal(BinaryInputStream in, BinaryContext /** * Get position to be used for handle. We assume here that the hdr byte was read, hence subtract -1. * + * @param in Input stream. * @return Position for handle. */ private static int positionForHandle(BinaryInputStream in) { diff --git a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderReader.java b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderReader.java index 2c650e8e75fbc..66562d280386d 100644 --- a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderReader.java +++ b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderReader.java @@ -491,7 +491,7 @@ public Object getValueQuickly(int pos, int len) { case GridBinaryMarshaller.OPTM_MARSH: { final BinaryInputStream bin = BinaryStreams.inputStream(arr, pos + 1); - final Object obj = BinaryImplUtils.doReadOptimized(bin, ctx, ctx.classLoader()); + final Object obj = BinaryImplUtils.doReadOptimized(bin, ctx, null); return obj; } @@ -843,7 +843,7 @@ else if (flag == GridBinaryMarshaller.DECIMAL) { case GridBinaryMarshaller.OPTM_MARSH: { final BinaryInputStream bin = BinaryStreams.inputStream(arr, pos); - final Object obj = BinaryImplUtils.doReadOptimized(bin, ctx, ctx.classLoader()); + final Object obj = BinaryImplUtils.doReadOptimized(bin, ctx, null); pos = bin.position(); diff --git a/modules/binary/impl/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedObjectInputStream.java b/modules/binary/impl/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedObjectInputStream.java index e1a41bda6ba53..6fe80a6ec938b 100644 --- a/modules/binary/impl/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedObjectInputStream.java +++ b/modules/binary/impl/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedObjectInputStream.java @@ -43,7 +43,6 @@ import java.util.concurrent.ConcurrentMap; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.marshaller.ClassLoaderUtils; -import org.apache.ignite.internal.util.CommonUtils; import org.apache.ignite.internal.util.GridUnsafe; import org.apache.ignite.internal.util.io.GridDataInput; import org.apache.ignite.internal.util.typedef.internal.SB; @@ -330,7 +329,7 @@ private Object readObject0() throws ClassNotFoundException, IOException { InvocationHandler ih = (InvocationHandler)readObject(); - return Proxy.newProxyInstance(clsLdr != null ? clsLdr : CommonUtils.gridClassLoader(), intfs, ih); + return Proxy.newProxyInstance(clsLdr, intfs, ih); case ENUM: case EXTERNALIZABLE: diff --git a/modules/binary/impl/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshallerImpl.java b/modules/binary/impl/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshallerImpl.java index e2f6d37bb9acb..1451be43174d4 100644 --- a/modules/binary/impl/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshallerImpl.java +++ b/modules/binary/impl/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshallerImpl.java @@ -116,9 +116,6 @@ else if (!(objFilter instanceof IgniteObjectInputFilter)) { @Override protected T unmarshal0(InputStream in, @Nullable ClassLoader clsLdr) throws IgniteCheckedException { assert in != null; - if (clsLdr == null) - clsLdr = getClass().getClassLoader(); - try (ObjectInputStream objIn = new JdkMarshallerObjectInputStream(new JdkMarshallerInputStreamWrapper(in), clsLdr)) { return (T)objIn.readObject(); } diff --git a/modules/binary/impl/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshallerObjectInputStream.java b/modules/binary/impl/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshallerObjectInputStream.java index 6a5c5cb6fbdb4..15705c559e67a 100644 --- a/modules/binary/impl/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshallerObjectInputStream.java +++ b/modules/binary/impl/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshallerObjectInputStream.java @@ -22,13 +22,14 @@ import java.io.ObjectInputStream; import java.io.ObjectStreamClass; import org.apache.ignite.internal.marshaller.ClassLoaderUtils; +import org.jetbrains.annotations.Nullable; /** * This class defines custom JDK object input stream. */ class JdkMarshallerObjectInputStream extends ObjectInputStream { /** */ - private final ClassLoader clsLdr; + private final @Nullable ClassLoader clsLdr; /** * @param in Parent input stream. @@ -38,8 +39,6 @@ class JdkMarshallerObjectInputStream extends ObjectInputStream { JdkMarshallerObjectInputStream(InputStream in, ClassLoader clsLdr) throws IOException { super(in); - assert clsLdr != null; - this.clsLdr = clsLdr; enableResolveObject(true); diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/ClusterMetricsSnapshotSerializeCompatibilityTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/ClusterMetricsSnapshotSerializeCompatibilityTest.java index a53338663ff17..d28dcd83fab6c 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/ClusterMetricsSnapshotSerializeCompatibilityTest.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/ClusterMetricsSnapshotSerializeCompatibilityTest.java @@ -20,11 +20,13 @@ import java.io.ByteArrayInputStream; import java.util.HashMap; import java.util.zip.ZipInputStream; +import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.marshaller.ClassLoaderUtils; import org.apache.ignite.internal.marshaller.optimized.OptimizedMarshaller; import org.apache.ignite.internal.processors.cache.CacheMetricsSnapshot; import org.apache.ignite.internal.processors.cluster.CacheMetricsMessage; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.marshaller.Marshaller; import org.apache.ignite.marshaller.MarshallerContextTestImpl; import org.apache.ignite.marshaller.Marshallers; import org.apache.ignite.testframework.GridTestUtils; @@ -43,7 +45,7 @@ public ClusterMetricsSnapshotSerializeCompatibilityTest() { /** */ @Test - public void testSerializationAndDeserialization() throws Exception { + public void testSerializationAndDeserialization() throws IgniteCheckedException { HashMap metrics = new HashMap<>(); metrics.put(1, createMetricsWithBorderMarker()); @@ -52,11 +54,7 @@ public void testSerializationAndDeserialization() throws Exception { byte[] zipMarshal = U.zip(U.marshal(marshaller, metrics)); - ZipInputStream in = new ZipInputStream(new ByteArrayInputStream(zipMarshal)); - - in.getNextEntry(); - - HashMap unmarshalMetrics = U.unmarshal(marshaller, in, null); + HashMap unmarshalMetrics = unmarshalZip(marshaller, zipMarshal); assertTrue(isMetricsEquals(metrics.get(1), unmarshalMetrics.get(1))); @@ -95,4 +93,29 @@ private OptimizedMarshaller marshaller() { return marsh; } + + /** + * @param marsh Marshaller. + * @param zipBytes Zip-compressed bytes. + * @return Unmarshalled object. + * @throws IgniteCheckedException + */ + private static T unmarshalZip(Marshaller marsh, byte[] zipBytes) throws IgniteCheckedException { + assert marsh != null; + assert zipBytes != null; + + try { + ZipInputStream in = new ZipInputStream(new ByteArrayInputStream(zipBytes)); + + in.getNextEntry(); + + return marsh.unmarshal(in, null); + } + catch (IgniteCheckedException e) { + throw e; + } + catch (Exception e) { + throw new IgniteCheckedException(e); + } + } } diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 38ee2eb4d9df0..3a66112f7d96a 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -414,10 +414,8 @@ private GridQueryFieldsResult executeSelectLocal( // Convert parameters into BinaryObjects. BinaryMarshaller m = ctx.marshaller(); byte[] paramsBytes = U.marshal(m, qryParams.arguments()); - final ClassLoader ldr = U.resolveClassLoader(ctx.config()); - Object[] params = BinaryUtils.rawArrayFromBinary(m.binaryMarshaller() - .unmarshal(paramsBytes, ldr)); + Object[] params = BinaryUtils.rawArrayFromBinary(m.binaryMarshaller().unmarshal(paramsBytes, null)); H2Utils.bindParameters(stmt, F.asList(params)); diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2DmlRequest.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2DmlRequest.java index 31a5de860155a..80f186fde6b64 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2DmlRequest.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2DmlRequest.java @@ -354,10 +354,8 @@ public GridH2DmlRequest queryInitiatorId(String qryInitiatorId) { assert paramsBytes != null; - final ClassLoader ldr = U.resolveClassLoader(ctx.config()); - // To avoid deserializing of enum types. - params = BinaryUtils.rawArrayFromBinary(ctx.marshaller().binaryMarshaller().unmarshal(paramsBytes, ldr)); + params = BinaryUtils.rawArrayFromBinary(ctx.marshaller().binaryMarshaller().unmarshal(paramsBytes, null)); } diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2DmlResponse.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2DmlResponse.java index 834b9f3996381..edfb767a2a226 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2DmlResponse.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2DmlResponse.java @@ -125,10 +125,8 @@ public String error() { if (errKeys != null || errKeysBytes == null) return; - final ClassLoader ldr = U.resolveClassLoader(ctx.config()); - // To avoid deserializing of enum types. - errKeys = BinaryUtils.rawArrayFromBinary(ctx.marshaller().binaryMarshaller().unmarshal(errKeysBytes, ldr)); + errKeys = BinaryUtils.rawArrayFromBinary(ctx.marshaller().binaryMarshaller().unmarshal(errKeysBytes, null)); } /** {@inheritDoc} */ diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2QueryRequest.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2QueryRequest.java index 85b91e92e1139..ef7d9223ace43 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2QueryRequest.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2QueryRequest.java @@ -543,10 +543,8 @@ public static Boolean isDataPageScanEnabled(int flags) { @Override public void unmarshall(GridKernalContext ctx) { assert paramsBytes != null; - final ClassLoader ldr = U.resolveClassLoader(ctx.config()); - // To avoid deserializing of enum types. - params = BinaryUtils.rawArrayFromBinary(ctx.marshaller().binaryMarshaller().unmarshal(paramsBytes, ldr)); + params = BinaryUtils.rawArrayFromBinary(ctx.marshaller().binaryMarshaller().unmarshal(paramsBytes, null)); }