Index: jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/PropertyInfoImpl.java =================================================================== --- jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/PropertyInfoImpl.java (revision 915358) +++ jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/PropertyInfoImpl.java (revision ) @@ -23,34 +23,33 @@ import javax.jcr.PropertyType; import javax.jcr.RepositoryException; -import java.util.ArrayList; -import java.util.List; /** * PropertyInfoImpl... */ public class PropertyInfoImpl extends ItemInfoImpl implements PropertyInfo { - private final boolean isMultiValued; + private final boolean multiValued; private PropertyId id; private int propertyType; - private List values = new ArrayList(); + private QValue[] values = QValue.EMPTY_ARRAY; public PropertyInfoImpl(PropertyId id, Path path, int propertyType, - QValue singleValue) throws RepositoryException { + QValue value) throws RepositoryException { super(path, false); this.id = id; this.propertyType = propertyType; - isMultiValued = false; - values.add(singleValue); + multiValued = false; + values = new QValue[]{value}; } - public PropertyInfoImpl(PropertyId id, Path path, int propertyType) throws RepositoryException { + public PropertyInfoImpl(PropertyId id, Path path, int propertyType, QValue[] values) throws RepositoryException { super(path, false); this.id = id; this.propertyType = propertyType; - isMultiValued = true; + this.values = values; + multiValued = true; } //-------------------------------------------------------< PropertyInfo >--- @@ -68,41 +67,24 @@ } public boolean isMultiValued() { - return isMultiValued; + return multiValued; } public QValue[] getValues() { - return values.toArray(new QValue[values.size()]); + return values; } //-------------------------------------------------------------------------- - int numberOfValues() { - return values.size(); - } - void setId(PropertyId id) { this.id = id; } - void addValue(QValue value) throws RepositoryException { - if (values == null) { - values = new ArrayList(); - } else if (!isMultiValued && !values.isEmpty()) { - throw new RepositoryException("Attempt to add multiple values to a single valued PropertyInfo"); - } - values.add(value); - } - - void setType(int propertyType) { - this.propertyType = propertyType; - } - void checkCompleted() throws RepositoryException { if (id == null) { throw new RepositoryException("Incomplete PropertyInfo: id missing."); } - if (values.size() == 0 && propertyType == PropertyType.UNDEFINED) { - throw new RepositoryException("Incomplete PropertyInfo: missing type of multivalued property."); + if (propertyType == PropertyType.UNDEFINED) { + throw new RepositoryException("Incomplete PropertyInfo: missing type of property."); } } } Index: jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/ValueLoader.java =================================================================== --- jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/ValueLoader.java (revision 927406) +++ jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/ValueLoader.java (revision ) @@ -94,7 +94,7 @@ //-------------------------------------------------------------------------- /** - * Internal inteface + * Internal interface */ interface Target { /** Index: jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/NodeInfoImpl.java =================================================================== --- jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/NodeInfoImpl.java (revision 937290) +++ jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/NodeInfoImpl.java (revision ) @@ -19,9 +19,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; -import java.util.LinkedHashSet; import java.util.List; -import java.util.Set; import javax.jcr.RepositoryException; @@ -32,7 +30,6 @@ import org.apache.jackrabbit.spi.NodeInfo; import org.apache.jackrabbit.spi.Path; import org.apache.jackrabbit.spi.PropertyId; -import org.apache.jackrabbit.spi.PropertyInfo; import org.apache.jackrabbit.spi.QValue; import org.apache.jackrabbit.spi.commons.name.NameConstants; @@ -41,13 +38,13 @@ */ public class NodeInfoImpl extends ItemInfoImpl implements NodeInfo { + // data deduced from property values private NodeId id; - private String uniqueID; private Name primaryNodeTypeName; private Name[] mixinNodeTypeNames = Name.EMPTY_ARRAY; - private final Set propertyInfos = new LinkedHashSet(); - private Set childInfos = null; + private final List propertyIds = new ArrayList(8); + private List childInfos = null; /** * Creates a new NodeInfo. @@ -83,70 +80,63 @@ } public Iterator getPropertyIds() { - List l = new ArrayList(); - for (PropertyInfo propertyInfo : propertyInfos) { - l.add(propertyInfo.getId()); + return propertyIds.iterator(); - } + } - return l.iterator(); - } public Iterator getChildInfos() { return (childInfos == null) ? null : childInfos.iterator(); } //-------------------------------------------------------------------------- - void addPropertyInfo(PropertyInfoImpl propInfo, IdFactory idFactory) throws RepositoryException { - propertyInfos.add(propInfo); - + void setPropertyInfos(PropertyInfoImpl[] propInfos, IdFactory idFactory) throws RepositoryException { + boolean resolveUUID = false; + for (PropertyInfoImpl propInfo : propInfos) { - Name pn = propInfo.getId().getName(); - if (NameConstants.JCR_UUID.equals(pn)) { + Name pn = propInfo.getId().getName(); + if (NameConstants.JCR_UUID.equals(pn)) { - uniqueID = propInfo.getValues()[0].getString(); - id = idFactory.createNodeId(uniqueID); + id = idFactory.createNodeId(propInfo.getValues()[0].getString()); + resolveUUID = true; - } else if (NameConstants.JCR_PRIMARYTYPE.equals(pn)) { - primaryNodeTypeName = propInfo.getValues()[0].getName(); - } else if (NameConstants.JCR_MIXINTYPES.equals(pn)) { - QValue[] vs = propInfo.getValues(); - Name[] mixins = new Name[vs.length]; - for (int i = 0; i < vs.length; i++) { - mixins[i] = vs[i].getName(); - } - mixinNodeTypeNames = mixins; - } - } + } else if (NameConstants.JCR_PRIMARYTYPE.equals(pn)) { + primaryNodeTypeName = propInfo.getValues()[0].getName(); + } else if (NameConstants.JCR_MIXINTYPES.equals(pn)) { + QValue[] vs = propInfo.getValues(); + Name[] mixins = new Name[vs.length]; + for (int i = 0; i < vs.length; i++) { + mixins[i] = vs[i].getName(); + } + mixinNodeTypeNames = mixins; + } + } - void resolveUUID(IdFactory idFactory) { - if (uniqueID != null) { - for (Object o : propertyInfos) { - PropertyInfoImpl propInfo = (PropertyInfoImpl) o; + propertyIds.clear(); + for (PropertyInfoImpl propInfo : propInfos) { + if (resolveUUID) { propInfo.setId(idFactory.createPropertyId(id, propInfo.getName())); } + propertyIds.add(propInfo.getId()); } + } void addChildInfo(ChildInfo childInfo) { if (childInfos == null) { - childInfos = new LinkedHashSet(); + childInfos = new ArrayList(); } childInfos.add(childInfo); } - void setNumberOfChildNodes(long numberOfChildNodes) { - if (numberOfChildNodes == 0) { - childInfos = Collections.emptySet(); - } // else: wait for calls to #addChildInfo + void markAsLeafNode() { + childInfos = Collections.emptyList(); } boolean isCompleted() { - return !(id == null || primaryNodeTypeName == null || propertyInfos.isEmpty()); + return (id != null && primaryNodeTypeName != null && !propertyIds.isEmpty()); } - void checkCompleted() throws RepositoryException { - if (!isCompleted()) { - throw new RepositoryException("Incomplete NodeInfo"); - } - } - String getUniqueID() { - return uniqueID; + if (id.getUniqueID() != null && id.getPath() == null) { + return id.getUniqueID(); + } else { + return null; - } -} \ No newline at end of file + } + } +} \ No newline at end of file Index: jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/util/StringCache.java =================================================================== --- jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/util/StringCache.java (revision ) +++ jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/util/StringCache.java (revision ) @@ -0,0 +1,174 @@ +/* + * 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.jackrabbit.spi.commons.util; + +import java.lang.ref.SoftReference; + +/** + * A few String utility functions. + */ +public class StringCache { + + public static final boolean OBJECT_CACHE = getBooleanSetting("jackrabbit.stringCache", true); + public static final int OBJECT_CACHE_SIZE = nextPowerOf2(getIntSetting("jackrabbit.stringCacheSize", 1024)); + + private static SoftReference softCache = new SoftReference(null); + + private StringCache() { + // utility class + } + + private static int nextPowerOf2(int x) { + long i = 1; + while (i < x && i < (Integer.MAX_VALUE / 2)) { + i += i; + } + return (int) i; + } + + private static boolean getBooleanSetting(String name, boolean defaultValue) { + String s = getProperty(name); + if (s != null) { + try { + return Boolean.valueOf(s).booleanValue(); + } catch (NumberFormatException e) { + // ignore + } + } + return defaultValue; + } + + private static int getIntSetting(String name, int defaultValue) { + String s = getProperty(name); + if (s != null) { + try { + return Integer.decode(s).intValue(); + } catch (NumberFormatException e) { + // ignore + } + } + return defaultValue; + } + + private static String getProperty(String name) { + try { + return System.getProperty(name); + } catch (Exception e) { + // SecurityException + // applets may not do that - ignore + return null; + } + } + + private static String[] getCache() { + String[] cache; + // softCache can be null due to a Tomcat problem + // a workaround is disable the system property org.apache. + // catalina.loader.WebappClassLoader.ENABLE_CLEAR_REFERENCES + if (softCache != null) { + cache = softCache.get(); + if (cache != null) { + return cache; + } + } + try { + cache = new String[OBJECT_CACHE_SIZE]; + } catch (OutOfMemoryError e) { + return null; + } + softCache = new SoftReference(cache); + return cache; + } + + /** + * Get the string from the cache if possible. If the string has not been + * found, it is added to the cache. If there is such a string in the cache, + * that one is returned. + * + * @param s the original string + * @return a string with the same content, if possible from the cache + */ + public static String cache(String s) { + if (!OBJECT_CACHE) { + return s; + } + if (s == null) { + return s; + } else if (s.length() == 0) { + return ""; + } + int hash = s.hashCode(); + String[] cache = getCache(); + if (cache != null) { + int index = hash & (OBJECT_CACHE_SIZE - 1); + String cached = cache[index]; + if (cached != null) { + if (s.equals(cached)) { + return cached; + } + } + cache[index] = s; + } + return s; + } + + /** + * Get a string from the cache, and if no such string has been found, create + * a new one with only this content. This solves out of memory problems if + * the string is a substring of another, large string. In Java, strings are + * shared, which could lead to memory problems. This avoid such problems. + * + * @param s the string + * @return a string that is guaranteed not be a substring of a large string + */ + public static String fromCacheOrNew(String s) { + if (!OBJECT_CACHE) { + return s; + } + if (s == null) { + return s; + } else if (s.length() == 0) { + return ""; + } + int hash = s.hashCode(); + String[] cache = getCache(); + int index = hash & (OBJECT_CACHE_SIZE - 1); + if (cache == null) { + return s; + } + String cached = cache[index]; + if (cached != null) { + if (s.equals(cached)) { + return cached; + } + } + // create a new object that is not shared + // (to avoid out of memory if it is a substring of a big String) + // NOPMD + s = new String(s); + cache[index] = s; + return s; + } + + /** + * Clear the cache. This method is used for testing. + */ + public static void clearCache() { + softCache = new SoftReference(null); + } + +} \ No newline at end of file Index: jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/ItemInfoJSONHandler.java =================================================================== --- jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/ItemInfoJSONHandler.java (revision 916295) +++ jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/ItemInfoJSONHandler.java (revision ) @@ -38,6 +38,8 @@ import org.apache.jackrabbit.spi.PropertyId; import org.apache.jackrabbit.spi.QValue; import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver; +import org.apache.jackrabbit.spi.commons.name.NameConstants; +import org.apache.jackrabbit.spi.commons.util.StringCache; import org.apache.jackrabbit.util.Text; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,7 +51,7 @@ private static Logger log = LoggerFactory.getLogger(ItemInfoJsonHandler.class); - private static final int SPECIAL_JSON_PAIR = Integer.MAX_VALUE; + private static final String LEAF_NODE_HINT = "::NodeIteratorSize"; private final List itemInfos; private final NamePathResolver resolver; @@ -59,13 +61,20 @@ private final PathFactory pFactory; private final IdFactory idFactory; + private boolean expectingHintValue = false; + private Name name; - private int propertyType; private int index = Path.INDEX_DEFAULT; + // temp. property state + private int propertyType; + private boolean multiValuedProperty = false; + private List propValues = new ArrayList(); + private Stack nodeInfos = new Stack(); - private PropertyInfoImpl mvPropInfo; + private Stack> propInfoLists = new Stack>(); + ItemInfoJsonHandler(NamePathResolver resolver, NodeInfo nInfo, String rootURI, QValueFactoryImpl vFactory, @@ -81,6 +90,7 @@ itemInfos = new ArrayList(); itemInfos.add(nInfo); nodeInfos.push(nInfo); + propInfoLists.push(new ArrayList(8)); } public void object() throws IOException { @@ -93,7 +103,7 @@ Path p = pFactory.create(currentPath, relPath, true); NodeInfo nInfo = new NodeInfoImpl(id, p); nodeInfos.push(nInfo); - itemInfos.add(nInfo); + propInfoLists.push(new ArrayList(8)); } catch (RepositoryException e) { throw new IOException(e.getMessage()); } @@ -103,7 +113,9 @@ public void endObject() throws IOException { try { NodeInfoImpl nInfo = (NodeInfoImpl) nodeInfos.pop(); - nInfo.resolveUUID(idFactory); + List props = propInfoLists.pop(); + // all required information to create a node info should now be gathered + nInfo.setPropertyInfos(props.toArray(new PropertyInfoImpl[props.size()]), idFactory); NodeInfo parent = getCurrentNodeInfo(); if (parent != null) { if (nInfo.getPath().getAncestor(1).equals(parent.getPath())) { @@ -113,62 +125,80 @@ log.debug("NodeInfo '"+ nInfo.getPath() + "' out of hierarchy. Parent path = " + parent.getPath()); } } - if (!nInfo.isCompleted()) { + if (nInfo.isCompleted()) { + itemInfos.addAll(props); + itemInfos.add(nInfo); + } else { log.debug("Incomplete NodeInfo '"+ nInfo.getPath() + "' -> Only present as ChildInfo with its parent."); - itemInfos.remove(nInfo); } } catch (RepositoryException e) { throw new IOException(e.getMessage()); + } finally { + // reset all node-related handler state + name = null; + index = Path.INDEX_DEFAULT; } } public void array() throws IOException { - try { - mvPropInfo = createPropertyInfo(null, true); - } catch (RepositoryException e) { - throw new IOException(e.getMessage()); + multiValuedProperty = true; + propValues.clear(); - } + } - } public void endArray() throws IOException { try { + if (propertyType == PropertyType.UNDEFINED) { + if (propValues.isEmpty()) { - // make sure that type is set for mv-properties with empty value array. + // make sure that type is set for mv-properties with empty value array. - if (propertyType == PropertyType.UNDEFINED && - mvPropInfo.numberOfValues() == 0) { - int type = vFactory.retrieveType(getValueURI()); - mvPropInfo.setType(type); + propertyType = vFactory.retrieveType(getValueURI()); + } else { + propertyType = propValues.get(0).getType(); - } + } - mvPropInfo.checkCompleted(); - getCurrentNodeInfo().addPropertyInfo(mvPropInfo, idFactory); - mvPropInfo = null; + } + // create multi-valued property info + NodeInfoImpl parent = getCurrentNodeInfo(); + Path p = pFactory.create(parent.getPath(), name, true); + PropertyId id = idFactory.createPropertyId(parent.getId(), name); + PropertyInfoImpl propInfo = new PropertyInfoImpl(id, p, propertyType, propValues.toArray(new QValue[propValues.size()])); + propInfo.checkCompleted(); + getCurrentPropInfos().add(propInfo); } catch (RepositoryException e) { throw new IOException(e.getMessage()); + } finally { + // reset property-related handler state + propertyType = PropertyType.UNDEFINED; + multiValuedProperty = false; + propValues.clear(); + name = null; } } public void key(String key) throws IOException { + expectingHintValue = false; try { - if (key.equals("::NodeIteratorSize")) { - propertyType = SPECIAL_JSON_PAIR; - // TODO: if additional JSON pairs are created -> set name + if (key.equals(LEAF_NODE_HINT)) { + expectingHintValue = true; + // TODO: remember name of hint if there will be additional types of hints + name = null; } else if (key.startsWith(":")) { - // binary property - name = resolver.getQName(key.substring(1)); - propertyType = PropertyType.BINARY; + expectingHintValue = true; + // either + // : : "PropertyTypeName" + // or + // : : + //name = resolver.getQName(key.substring(1)); + name = resolver.getQName(StringCache.fromCacheOrNew(key.substring(1))); index = Path.INDEX_DEFAULT; } else if (key.endsWith("]")) { // sns-node name int pos = key.lastIndexOf('['); - name = resolver.getQName(key.substring(0, pos)); + //name = resolver.getQName(key.substring(0, pos)); + name = resolver.getQName(StringCache.fromCacheOrNew(key.substring(0, pos))); propertyType = PropertyType.UNDEFINED; index = Integer.parseInt(key.substring(pos + 1, key.length() - 1)); } else { // either node or property - Name previousName = name; - name = resolver.getQName(key); - propertyType = guessPropertyType(name, previousName); - // property type is defined through json value OR special property - // :propertyName = type. + name = resolver.getQName(StringCache.cache(key)); index = Path.INDEX_DEFAULT; } } catch (RepositoryException e) { @@ -176,21 +206,27 @@ } } + /** + * there is currently one special string-value hint: + * + * : : "PropertyTypeName" + * + * @param value The value. + * @throws IOException + */ public void value(String value) throws IOException { + if (expectingHintValue) { + // : : "PropertyTypeName" + propertyType = PropertyType.valueFromName(value); + return; + } try { QValue v; switch (propertyType) { - case SPECIAL_JSON_PAIR: - // currently no special boolean value pair -> ignore - return; - case PropertyType.BINARY: - // key started with ':' but value is String instead of - // long. value therefore reflects the property type. - // -> reset the property type. - // -> omit creation of value AND call to value(QValue) - propertyType = PropertyType.valueFromName(value); - return; case PropertyType.UNDEFINED: + if (!NameConstants.JCR_UUID.equals(name)) { + value = StringCache.cache(value); + } v = vFactory.create(value, PropertyType.STRING); break; case PropertyType.NAME: @@ -209,8 +245,8 @@ } public void value(boolean value) throws IOException { - if (propertyType == SPECIAL_JSON_PAIR) { - // currently no special boolean value pair -> ignore + if (expectingHintValue) { + // there are currently no special boolean value hints: return; } try { @@ -220,30 +256,46 @@ } } + /** + * there are currently 2 types of special long value hints: + * + * a) ::NodeIteratorSize : 0 + * ==> denotes the current node as leaf node + * + * b) : : + * + * @param value The value. + * @throws IOException + */ public void value(long value) throws IOException { - if (propertyType == SPECIAL_JSON_PAIR) { + if (expectingHintValue) { + if (name == null) { + // ::NodeIteratorSize : 0 - NodeInfoImpl parent = getCurrentNodeInfo(); - if (parent != null) { + NodeInfoImpl parent = getCurrentNodeInfo(); + if (parent != null) { - parent.setNumberOfChildNodes(value); + parent.markAsLeafNode(); - } + } + } else { + // : : + propertyType = PropertyType.BINARY; + try { + int indx = (!multiValuedProperty) ? -1 : propValues.size(); + value(vFactory.create(value, getValueURI(), indx)); + } catch (RepositoryException e) { + throw new IOException(e.getMessage()); + } + } return; } try { - QValue v; - if (propertyType == PropertyType.BINARY) { - int indx = (mvPropInfo == null) ? -1 : mvPropInfo.numberOfValues(); - v = vFactory.create(value, getValueURI(), indx); - } else { - v = vFactory.create(value); - } - value(v); + value(vFactory.create(value)); } catch (RepositoryException e) { throw new IOException(e.getMessage()); } } public void value(double value) throws IOException { - if (propertyType == SPECIAL_JSON_PAIR) { + if (expectingHintValue) { // currently no special double value pair -> ignore return; } @@ -261,10 +313,31 @@ * @throws RepositoryException */ private void value(QValue value) throws RepositoryException { - if (mvPropInfo == null) { - createPropertyInfo(value, false); + if (!multiValuedProperty) { + try { + if (propertyType == PropertyType.UNDEFINED) { + propertyType = value.getType(); + } + // create single-valued property info + NodeInfoImpl parent = getCurrentNodeInfo(); + Path p = pFactory.create(parent.getPath(), name, true); + PropertyId id = idFactory.createPropertyId(parent.getId(), name); + PropertyInfoImpl propInfo = new PropertyInfoImpl(id, p, propertyType, value); + propInfo.checkCompleted(); + // add property info to current list, will be processed on endObject() event + getCurrentPropInfos().add(propInfo); + } finally { + // reset property-related handler state + propertyType = PropertyType.UNDEFINED; + multiValuedProperty = false; + propValues.clear(); + name = null; + expectingHintValue = false; + } } else { - mvPropInfo.addValue(value); + // multi-valued property + // add value to current list, will be processed on endArray() event + propValues.add(value); } } @@ -273,48 +346,17 @@ } private NodeInfoImpl getCurrentNodeInfo() { - return (nodeInfos.isEmpty()) ? null : (NodeInfoImpl) nodeInfos.peek(); + return (nodeInfos.isEmpty()) ? null : (NodeInfoImpl) nodeInfos.peek(); } - private PropertyInfoImpl createPropertyInfo(QValue value, boolean isMultiValued) throws RepositoryException { - NodeInfoImpl parent = getCurrentNodeInfo(); - Path p = pFactory.create(parent.getPath(), name, true); - PropertyId id = idFactory.createPropertyId(parent.getId(), name); - - PropertyInfoImpl pInfo; - if (isMultiValued) { - pInfo = new PropertyInfoImpl(id, p, propertyType); - // not added to parent but upon having read all values. - } else { - pInfo = new PropertyInfoImpl(id, p, propertyType, value); - parent.addPropertyInfo(pInfo, idFactory); + private List getCurrentPropInfos() { + return (propInfoLists.isEmpty()) ? null : propInfoLists.peek(); - } + } - itemInfos.add(pInfo); - return pInfo; - } private String getValueURI() throws RepositoryException { - Path propertyPath; - if (mvPropInfo == null) { - propertyPath = pFactory.create(getCurrentNodeInfo().getPath(), name, true); - } else { - propertyPath = mvPropInfo.getPath(); - } + Path propertyPath = pFactory.create(getCurrentNodeInfo().getPath(), name, true); StringBuffer sb = new StringBuffer(rootURI); sb.append(Text.escapePath(resolver.getJCRPath(propertyPath))); return sb.toString(); } - - private int guessPropertyType(Name name, Name previousName) { - if (name.equals(previousName)) { - // property has been previously retrieved from :name : "typeName" - // entry in the JSON string. if by coincidence the previous key - // is equal but belongs to an JSON object (-> node) the prop type - // has been reset to UNDEFINED anyway. - return propertyType; - } else { - // default: determine type upon Property.getType() only. - return PropertyType.UNDEFINED; - } +} - } -}