ignite-950: getting fields through reflection when class peresents on node
Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/28f8edaf Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/28f8edaf Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/28f8edaf Branch: refs/heads/ignite-950 Commit: 28f8edafdfc72f8779143337501cb99d6e697946 Parents: 2e8bdec Author: Denis Magda <dma...@gridgain.com> Authored: Mon Jun 29 13:51:10 2015 +0300 Committer: Denis Magda <dma...@gridgain.com> Committed: Mon Jun 29 13:51:10 2015 +0300 ---------------------------------------------------------------------- .../cache/CacheIndexedObjectImpl.java | 113 +++++++++++------- .../processors/cache/CacheObjectContext.java | 17 +-- .../cache/KeyCacheIndexedObjectImpl.java | 25 +--- .../cacheobject/IgniteCacheObjectProcessor.java | 14 ++- .../IgniteCacheObjectProcessorImpl.java | 16 +-- .../processors/query/GridQueryProcessor.java | 114 ++++++++++++++----- .../optimized/IgniteFieldNotFoundException.java | 11 ++ 7 files changed, 192 insertions(+), 118 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28f8edaf/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 8cf7085..7963245 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 @@ -26,6 +26,7 @@ import org.jetbrains.annotations.*; import sun.misc.*; import java.io.*; +import java.lang.reflect.*; import java.nio.*; import java.util.concurrent.*; @@ -44,6 +45,9 @@ public class CacheIndexedObjectImpl extends CacheObjectAdapter { private static final long BYTE_ARR_OFF = UNSAFE.arrayBaseOffset(byte[].class); /** */ + private Boolean hasClass; + + /** */ protected int start; /** */ @@ -93,9 +97,6 @@ public class CacheIndexedObjectImpl extends CacheObjectAdapter { public CacheIndexedObjectImpl(Object val, byte[] valBytes, int start, int len) { assert val != null || (valBytes != null && start >= 0 && len > 0); - if (valBytes != null && val != null) - val = null; - this.val = val; this.valBytes = valBytes; this.start = start; @@ -111,25 +112,25 @@ public class CacheIndexedObjectImpl extends CacheObjectAdapter { @Override public byte[] valueBytes(CacheObjectContext ctx) throws IgniteCheckedException { toMarshaledFormIfNeeded(ctx); - shrinkToSize(); - return valBytes; } /** {@inheritDoc} */ @Override public CacheObject prepareForCache(CacheObjectContext ctx) { - return detach(); + return this; } /** {@inheritDoc} */ @Override public void finishUnmarshal(CacheObjectContext ctx, ClassLoader ldr) throws IgniteCheckedException { - // No-op + assert valBytes != null; + + if (val == null && keepDeserialized(ctx, true)) + val = ctx.processor().unmarshal(ctx, valBytes, start, len, ldr); } /** {@inheritDoc} */ @Override public void prepareMarshal(CacheObjectContext ctx) throws IgniteCheckedException { toMarshaledFormIfNeeded(ctx); - shrinkToSize(); } /** {@inheritDoc} */ @@ -164,10 +165,21 @@ public class CacheIndexedObjectImpl extends CacheObjectAdapter { * * @param fieldName Field name. * @param marsh Marshaller. + * @param field Field instance to get access through reflection. * @return {@code true} if has. * @throws IgniteCheckedException In case of error. */ - public boolean hasField(String fieldName, OptimizedMarshallerExt marsh) throws IgniteCheckedException { + public boolean hasField(String fieldName, OptimizedMarshallerExt marsh, Field field) throws IgniteCheckedException { + if (field != null && val != null) { + try { + field.get(val); + return true; + } + catch (Exception e) { + return false; + } + } + assert valBytes != null; return marsh.hasField(fieldName, valBytes, start, len); @@ -178,11 +190,22 @@ public class CacheIndexedObjectImpl extends CacheObjectAdapter { * * @param fieldName Field name. * @param marsh Marshaller. + * @param field Field instance to get access through reflection. * @return Field. * @throws IgniteFieldNotFoundException In case if there is no such a field. * @throws IgniteCheckedException In case of error. */ - public Object field(String fieldName, OptimizedMarshallerExt marsh) throws IgniteCheckedException { + public Object field(String fieldName, OptimizedMarshallerExt marsh, Field field) throws IgniteCheckedException { + if (field != null && val != null) { + try { + return field.get(val); + } + catch (Exception e) { + throw new IgniteFieldNotFoundException("Object doesn't have the field [obj=" + val + ", field=" + + fieldName + "]", e); + } + } + assert valBytes != null; return marsh.readField(fieldName, valBytes, start, len, val != null ? val.getClass().getClassLoader() : null); @@ -204,8 +227,8 @@ public class CacheIndexedObjectImpl extends CacheObjectAdapter { Object val = ctx.processor().unmarshal(ctx, valBytes, start, len, ctx.kernalContext().config().getClassLoader()); - //if (ctx.storeValue()) - // this.val = val; + if (keepDeserialized(ctx, false)) + this.val = val; return val; } @@ -314,27 +337,6 @@ public class CacheIndexedObjectImpl extends CacheObjectAdapter { } /** - * Detaches object. - * - * @return Detached object wrapped by {@code CacheIndexedObjectImpl}. - */ - protected CacheIndexedObjectImpl detach() { - shrinkToSize(); - - return this; - } - - /** - * Checks whether the object is already detached or not. - * - * @return {@code true} if detached. - */ - protected boolean detached() { - return true; - //return start == 0 && len == valBytes.length; - } - - /** * Marshals {@link #val} to {@link #valBytes} if needed. * * @param ctx Cache object context. @@ -349,22 +351,49 @@ public class CacheIndexedObjectImpl extends CacheObjectAdapter { start = 0; len = valBytes.length; - val = null; + if (!keepDeserialized(ctx, false)) + val = null; } } /** - * Shrinks byte array to size boundaries. + * Checks whether to keep deserialized version of the object or not. + * + * @param ctx Cache object context. + * @param checkCls Check class definition presence on node flag. + * @return {@code true} if keep, {@code false} otherwise. */ - private void shrinkToSize() { - if (detached()) - return; + protected boolean keepDeserialized(CacheObjectContext ctx, boolean checkCls) { + if (ctx.copyOnGet()) + return false; - byte[] arr = new byte[len]; + return checkCls ? hasClassOnNode(ctx) : true; + } - U.arrayCopy(valBytes, start, arr, 0, len); + /** + * Checks whether a node has a class definition of a marhsaller object or not. + * + * @param ctx Cache object context. + * @return {@code true} if has, {@code false} otherwise. + */ + private boolean hasClassOnNode(CacheObjectContext ctx) { + if (val != null) + return true; + + if (hasClass != null) + return hasClass; + + assert valBytes != null; + + try { + Class<?> cls = ctx.kernalContext().marshallerContext().getClass(typeId(), null); + + hasClass = cls != null; + } + catch (Exception e) { + hasClass = false; + } - valBytes = arr; - start = 0; + return hasClass; } } http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28f8edaf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectContext.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectContext.java index 4e5ca5f..74e8ad5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectContext.java @@ -48,27 +48,23 @@ public class CacheObjectContext { /** */ private boolean p2pEnabled; - /** */ - private boolean systemCache; - /** * @param kernalCtx Kernal context. * @param dfltAffMapper Default affinity mapper. * @param cpyOnGet Copy on get flag. * @param storeVal {@code True} if should store unmarshalled value in cache. - * @param systemCache Whether the object will be stored in a system cache or not. + * @param */ public CacheObjectContext(GridKernalContext kernalCtx, AffinityKeyMapper dfltAffMapper, boolean cpyOnGet, - boolean storeVal, - boolean systemCache) { + boolean storeVal + ) { this.kernalCtx = kernalCtx; this.p2pEnabled = kernalCtx.config().isPeerClassLoadingEnabled(); this.dfltAffMapper = dfltAffMapper; this.cpyOnGet = cpyOnGet; this.storeVal = storeVal; - this.systemCache = systemCache; proc = kernalCtx.cacheObjects(); } @@ -95,13 +91,6 @@ public class CacheObjectContext { } /** - * @return {@code true} if the object is stored in a system cache. - */ - public boolean systemCache() { - return systemCache; - } - - /** * @return Default affinity mapper. */ public AffinityKeyMapper defaultAffMapper() { http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28f8edaf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheIndexedObjectImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheIndexedObjectImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheIndexedObjectImpl.java index e9c8973..e0a0c8d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheIndexedObjectImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheIndexedObjectImpl.java @@ -56,21 +56,10 @@ public class KeyCacheIndexedObjectImpl extends CacheIndexedObjectImpl implements } /** {@inheritDoc} */ - @SuppressWarnings("unchecked") - @Nullable @Override public <T> T value(CacheObjectContext ctx, boolean cpy) { - return (T)this; - } - - /** {@inheritDoc} */ - @Override public CacheObject prepareForCache(CacheObjectContext ctx) { - return this; - } - - /** {@inheritDoc} */ @Override public void finishUnmarshal(CacheObjectContext ctx, ClassLoader ldr) throws IgniteCheckedException { assert val != null || valBytes != null; - if (val == null && ctx.storeValue()) + if (val == null) val = ctx.processor().unmarshal(ctx, valBytes, start, len, ldr); } @@ -88,13 +77,6 @@ public class KeyCacheIndexedObjectImpl extends CacheIndexedObjectImpl implements } /** {@inheritDoc} */ - @Override public Object deserialize(CacheObjectContext ctx) { - assert val != null; - - return val; - } - - /** {@inheritDoc} */ @Override public int hashCode() { assert val != null; @@ -110,4 +92,9 @@ public class KeyCacheIndexedObjectImpl extends CacheIndexedObjectImpl implements return val.equals(other.val); } + + /** {@inheritDoc} */ + @Override protected boolean keepDeserialized(CacheObjectContext ctx, boolean checkCls) { + return true; + } } http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28f8edaf/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 7d1eec3..aa5a550 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 @@ -25,6 +25,8 @@ import org.apache.ignite.internal.processors.cache.*; import org.apache.ignite.marshaller.optimized.*; import org.jetbrains.annotations.*; +import java.lang.reflect.*; + /** * Cache objects processor. */ @@ -82,21 +84,25 @@ public interface IgniteCacheObjectProcessor extends GridProcessor { public boolean isPortableEnabled(); /** - * @param obj Portable object to get field from. + * Retrieves field from the given object. Object should be an instance of {@link CacheObject}. + * + * @param obj Object to get field from. * @param fieldName Field name. + * @param field Field instance to get access through reflection. * @throws IgniteFieldNotFoundException In case if there is no such a field. * @return Field value. */ - public Object field(Object obj, String fieldName) throws IgniteFieldNotFoundException; + public Object field(Object obj, String fieldName, @Nullable Field field) throws IgniteFieldNotFoundException; /** - * Checks whether field is set in the object. + * Checks whether field is set in the object. Object should be an instance of {@link CacheObject}. * * @param obj Object. * @param fieldName Field name. + * @param field Field instance to get access through reflection. * @return {@code true} if field is set. */ - public boolean hasField(Object obj, String fieldName); + public boolean hasField(Object obj, String fieldName, @Nullable Field field); /** * Checks whether this functionality is globally supported. http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28f8edaf/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 730b5d5..3bca8ee 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 @@ -31,6 +31,7 @@ import org.apache.ignite.marshaller.*; import org.apache.ignite.marshaller.optimized.*; import org.jetbrains.annotations.*; +import java.lang.reflect.*; import java.math.*; import java.util.*; import java.util.concurrent.*; @@ -290,8 +291,7 @@ public class IgniteCacheObjectProcessorImpl extends GridProcessorAdapter impleme CacheObjectContext res = new CacheObjectContext(ctx, ccfg.getAffinityMapper() != null ? ccfg.getAffinityMapper() : new GridCacheDefaultAffinityKeyMapper(), ccfg.isCopyOnRead() && memMode != OFFHEAP_VALUES, - storeVal, - GridCacheUtils.isSystemCache(ccfg.getName())); + storeVal); ctx.resource().injectGeneric(res.defaultAffMapper()); @@ -334,11 +334,11 @@ public class IgniteCacheObjectProcessorImpl extends GridProcessorAdapter impleme } /** {@inheritDoc} */ - @Override public Object field(Object obj, String fieldName) throws IgniteFieldNotFoundException { + @Override public Object field(Object obj, String fieldName, Field field) throws IgniteFieldNotFoundException { assert optMarshExt != null; try { - return ((CacheIndexedObjectImpl)obj).field(fieldName, optMarshExt); + return ((CacheIndexedObjectImpl)obj).field(fieldName, optMarshExt, field); } catch (IgniteFieldNotFoundException e) { throw e; @@ -353,12 +353,12 @@ public class IgniteCacheObjectProcessorImpl extends GridProcessorAdapter impleme } /** {@inheritDoc} */ - @Override public boolean hasField(Object obj, String fieldName) { + @Override public boolean hasField(Object obj, String fieldName, Field field) { if (obj instanceof CacheIndexedObjectImpl) { assert optMarshExt != null; try { - return ((CacheIndexedObjectImpl)obj).hasField(fieldName, optMarshExt); + return ((CacheIndexedObjectImpl)obj).hasField(fieldName, optMarshExt, null); } catch (IgniteCheckedException e) { throw new IgniteException(e); @@ -511,7 +511,7 @@ public class IgniteCacheObjectProcessorImpl extends GridProcessorAdapter impleme try { toMarshaledFormIfNeeded(ctx); - /*if (ctx.storeValue()) { + if (keepDeserialized(ctx, true)) { ClassLoader ldr = ctx.p2pEnabled() ? IgniteUtils.detectClass(this.val).getClassLoader() : val.getClass().getClassLoader(); @@ -519,7 +519,7 @@ public class IgniteCacheObjectProcessorImpl extends GridProcessorAdapter impleme ctx.processor().unmarshal(ctx, valBytes, start, len, ldr); return new CacheIndexedObjectImpl(val, valBytes, start, len); - }*/ + } return new CacheIndexedObjectImpl(null, valBytes, start, len); } http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28f8edaf/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java index 3ce561a..14e69bf 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java @@ -130,25 +130,23 @@ public class GridQueryProcessor extends GridProcessorAdapter { TypeDescriptor desc = new TypeDescriptor(); - Class<?> valCls = U.classForName(meta.getValueType(), null); + Class<?> keyCls = meta.getKeyType() != null ? U.classForName(meta.getKeyType(), null) : null; + Class<?> valCls = meta.getValueType() != null ? U.classForName(meta.getValueType(), null) : null; desc.name(valCls != null ? typeName(valCls) : meta.getValueType()); desc.valueClass(valCls != null ? valCls : Object.class); - desc.keyClass( - meta.getKeyType() == null ? - Object.class : - U.classForName(meta.getKeyType(), Object.class)); + desc.keyClass(keyCls != null ? keyCls : Object.class); TypeId typeId; if (valCls == null || ctx.cacheObjects().isPortableEnabled()) { - processCacheTypeMeta(meta, desc, PORTABLE_PROPERTY); + processCacheTypeMeta(meta, desc, PORTABLE_PROPERTY, keyCls, valCls); typeId = new TypeId(ccfg.getName(), ctx.cacheObjects().typeId(meta.getValueType())); } else if (ctx.cacheObjects().enableFieldsIndexing(valCls)) { - processCacheTypeMeta(meta, desc, INDEXED_FIELDS_PROPERTY); + processCacheTypeMeta(meta, desc, INDEXED_FIELDS_PROPERTY, keyCls, valCls); typeId = new TypeId(ccfg.getName(), ctx.cacheObjects().typeId(valCls.getName())); } @@ -1240,17 +1238,19 @@ public class GridQueryProcessor extends GridProcessorAdapter { * * @param meta Declared metadata. * @param d Type descriptor. - * @param propertyType PropertyType. + * @param propType PropertyType. + * @param keyCls Key class. + * @param valCls Value class. * @throws IgniteCheckedException If failed. */ - private void processCacheTypeMeta(CacheTypeMetadata meta, TypeDescriptor d, PropertyType propertyType) - throws IgniteCheckedException { - assert propertyType != CLASS_PROPERTY; + private void processCacheTypeMeta(CacheTypeMetadata meta, TypeDescriptor d, PropertyType propType, + @Nullable Class<?> keyCls, @Nullable Class<?> valCls) throws IgniteCheckedException { + assert propType != CLASS_PROPERTY; for (Map.Entry<String, Class<?>> entry : meta.getAscendingFields().entrySet()) { - Property prop = propertyType == PORTABLE_PROPERTY ? + Property prop = propType == PORTABLE_PROPERTY ? buildPortableProperty(entry.getKey(), entry.getValue()) : - buildIndexedFieldsProperty(entry.getKey(), entry.getValue()); + buildIndexedFieldsProperty(entry.getKey(), entry.getValue(), keyCls, valCls); d.addProperty(prop, false); @@ -1262,9 +1262,9 @@ public class GridQueryProcessor extends GridProcessorAdapter { } for (Map.Entry<String, Class<?>> entry : meta.getDescendingFields().entrySet()) { - Property prop = propertyType == PORTABLE_PROPERTY ? + Property prop = propType == PORTABLE_PROPERTY ? buildPortableProperty(entry.getKey(), entry.getValue()) : - buildIndexedFieldsProperty(entry.getKey(), entry.getValue()); + buildIndexedFieldsProperty(entry.getKey(), entry.getValue(), keyCls, valCls); d.addProperty(prop, false); @@ -1276,9 +1276,9 @@ public class GridQueryProcessor extends GridProcessorAdapter { } for (String txtIdx : meta.getTextFields()) { - Property prop = propertyType == PORTABLE_PROPERTY ? + Property prop = propType == PORTABLE_PROPERTY ? buildPortableProperty(txtIdx, String.class) : - buildIndexedFieldsProperty(txtIdx, String.class); + buildIndexedFieldsProperty(txtIdx, String.class, keyCls, valCls); d.addProperty(prop, false); @@ -1296,9 +1296,9 @@ public class GridQueryProcessor extends GridProcessorAdapter { int order = 0; for (Map.Entry<String, IgniteBiTuple<Class<?>, Boolean>> idxField : idxFields.entrySet()) { - Property prop = propertyType == PORTABLE_PROPERTY ? + Property prop = propType == PORTABLE_PROPERTY ? buildPortableProperty(idxField.getKey(), idxField.getValue().get1()) : - buildIndexedFieldsProperty(idxField.getKey(), idxField.getValue().get1()); + buildIndexedFieldsProperty(idxField.getKey(), idxField.getValue().get1(), keyCls, valCls); d.addProperty(prop, false); @@ -1312,9 +1312,9 @@ public class GridQueryProcessor extends GridProcessorAdapter { } for (Map.Entry<String, Class<?>> entry : meta.getQueryFields().entrySet()) { - Property prop = propertyType == PORTABLE_PROPERTY ? + Property prop = propType == PORTABLE_PROPERTY ? buildPortableProperty(entry.getKey(), entry.getValue()) : - buildIndexedFieldsProperty(entry.getKey(), entry.getValue()); + buildIndexedFieldsProperty(entry.getKey(), entry.getValue(), keyCls, valCls); if (!d.props.containsKey(prop.name())) d.addProperty(prop, false); @@ -1421,15 +1421,18 @@ public class GridQueryProcessor extends GridProcessorAdapter { * @param pathStr String representing path to the property. May contains dots '.' to identify * nested fields. * @param resType Result type. + * @param keyCls Key class. + * @param valCls Value class. * @return Portable property. */ - private IndexedFieldsProperty buildIndexedFieldsProperty(String pathStr, Class<?> resType) { + private IndexedFieldsProperty buildIndexedFieldsProperty(String pathStr, Class<?> resType, + @Nullable Class<?> keyCls, @Nullable Class<?> valCls) { String[] path = pathStr.split("\\."); IndexedFieldsProperty res = null; for (String prop : path) - res = new IndexedFieldsProperty(prop, res, resType); + res = new IndexedFieldsProperty(prop, res, resType, keyCls, valCls); return res; } @@ -1699,9 +1702,9 @@ public class GridQueryProcessor extends GridProcessorAdapter { if (isKeyProp0 == 0) { // Key is allowed to be a non-portable object here. // We check key before value consistently with ClassProperty. - if (ctx.cacheObjects().isPortableObject(key) && ctx.cacheObjects().hasField(key, propName)) + if (ctx.cacheObjects().isPortableObject(key) && ctx.cacheObjects().hasField(key, propName, null)) isKeyProp = isKeyProp0 = 1; - else if (ctx.cacheObjects().hasField(val, propName)) + else if (ctx.cacheObjects().hasField(val, propName, null)) isKeyProp = isKeyProp0 = -1; else { U.warn(log, "Neither key nor value have property " + @@ -1714,7 +1717,7 @@ public class GridQueryProcessor extends GridProcessorAdapter { obj = isKeyProp0 == 1 ? key : val; } - return ctx.cacheObjects().field(obj, propName); + return ctx.cacheObjects().field(obj, propName, null); } /** {@inheritDoc} */ @@ -1741,17 +1744,49 @@ public class GridQueryProcessor extends GridProcessorAdapter { /** Result class. */ private Class<?> type; + /** Key field */ + private Field keyField; + + /** Value field */ + private Field valueField; + /** * Constructor. * * @param propName Property name. * @param parent Parent property. * @param type Result type. + * @param keyCls Key class. + * @param valCls Value class. */ - private IndexedFieldsProperty(String propName, IndexedFieldsProperty parent, Class<?> type) { + private IndexedFieldsProperty(String propName, IndexedFieldsProperty parent, Class<?> type, + @Nullable Class<?> keyCls, @Nullable Class<?> valCls) { this.propName = propName; this.parent = parent; this.type = type; + + if (keyCls != null) { + try { + keyField = keyCls.getDeclaredField(propName); + + keyField.setAccessible(true); + } catch (NoSuchFieldException e) { + // No-op + } + } + else if (valCls != null && keyField == null) { + try { + valueField = valCls.getDeclaredField(propName); + + valueField.setAccessible(true); + } catch (NoSuchFieldException e) { + // No-op + } + } + + if ((keyCls != null || valCls != null) && keyField == null && valueField == null) + U.warn(log, "Neither key nor value class has field " + + "[fieldName=" + propName + ", key=" + keyCls + ", val=" + valCls + "]"); } /** {@inheritDoc} */ @@ -1768,28 +1803,45 @@ public class GridQueryProcessor extends GridProcessorAdapter { throw new IgniteCheckedException("Non-indexed object received as a result of property extraction " + "[parent=" + parent + ", propName=" + propName + ", obj=" + obj + ']'); - return ctx.cacheObjects().field(obj, propName); + return ctx.cacheObjects().field(obj, propName, keyField != null ? keyField : valueField); } else { if (key instanceof CacheIndexedObjectImpl) { try { - return ctx.cacheObjects().field(key, propName); + + return ctx.cacheObjects().field(key, propName, keyField); } catch (IgniteFieldNotFoundException e) { // Ignore } } + else if (keyField != null) { + try { + return keyField.get(key); + } + catch (Exception e) { + throw new IgniteCheckedException(e); + } + } if (val instanceof CacheIndexedObjectImpl) { try { - return ctx.cacheObjects().field(val, propName); + return ctx.cacheObjects().field(val, propName, valueField); } catch (IgniteFieldNotFoundException e) { // Ignore } } + else if (valueField != null) { + try { + return valueField.get(val); + } + catch (Exception e) { + throw new IgniteCheckedException(e); + } + } - U.warn(log, "Neither key nor value have property " + + U.warn(log, "Neither key nor value has property " + "[propName=" + propName + ", key=" + key + ", val=" + val + "]"); return null; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28f8edaf/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/IgniteFieldNotFoundException.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/IgniteFieldNotFoundException.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/IgniteFieldNotFoundException.java index e5c3b5f..ac9808f 100644 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/IgniteFieldNotFoundException.java +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/IgniteFieldNotFoundException.java @@ -18,6 +18,7 @@ package org.apache.ignite.marshaller.optimized; import org.apache.ignite.*; +import org.jetbrains.annotations.*; /** * Exception is thrown when there is an attempt to retrieve or deserialize an unexisting field from byte array @@ -35,4 +36,14 @@ public class IgniteFieldNotFoundException extends IgniteCheckedException { public IgniteFieldNotFoundException(String msg) { super(msg); } + + /** + * Creates new exception with given error message and optional nested exception. + * + * @param msg Error message. + * @param cause Optional nested exception (can be {@code null}). + */ + public IgniteFieldNotFoundException(String msg, @Nullable Throwable cause) { + super(msg, cause); + } }