Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java (revision 769) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java (working copy) @@ -29,7 +29,6 @@ import java.util.List; import java.util.Set; import java.util.Stack; -import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.Value; import javax.jcr.nodetype.NodeDefinition; @@ -38,10 +37,6 @@ import net.jcip.annotations.Immutable; import org.jboss.dna.common.util.CheckArg; import org.jboss.dna.graph.property.Name; -import org.jboss.dna.graph.property.Path; -import org.jboss.dna.graph.property.ValueFactories; -import org.jboss.dna.graph.property.ValueFormatException; -import org.jboss.dna.graph.property.Path.Segment; /** * DNA implementation of JCR {@link NodeType}s. @@ -329,100 +324,16 @@ if (value == null) { return !property.isMandatory(); } - - return canCastValueToType(value, property.getRequiredType()); - } - - /** - * Internal method to validate that a value can be cast to a given JCR property type. The values are set according to the - * following rules: - *
    - *
  1. If property.getRequiredType() is {@link PropertyType#UNDEFINED}, return true
  2. - *
  3. Compare the type of the given value to the required type and see if they are compatible based on the rules in the JCR - * 1.0 spec.
  4. - *
- * - * @param jcrPropertyType a value from the {@link PropertyType} constants to which this value MAY be able to be casted. - * @param value the value to set (may not be null) - * @return whether the value can be cast to the given property type - */ - private boolean canCastValueToType( Value value, - int jcrPropertyType ) { - assert value != null; - - int valueType = value.getType(); - - // Trivial case - no cast required - if (valueType == jcrPropertyType) { - return true; - } - + try { - switch (jcrPropertyType) { - case PropertyType.BOOLEAN: - if (valueType == PropertyType.STRING) { - return true; - } - - if (valueType == PropertyType.BINARY) { - // If the binary can be converted to a UTF-8 string, it can be set onto a boolean property - value.getString(); - return true; - } - return false; - - case PropertyType.DATE: - if (valueType == PropertyType.DOUBLE || valueType == PropertyType.LONG) { - return true; - } - - if (valueType == PropertyType.STRING || valueType == PropertyType.BINARY) { - // If the binary can be converted to a date, it can be set onto a date property - value.getDate(); - return true; - } - return false; - - case PropertyType.NAME: - ValueFactories valueFactories = session.getExecutionContext().getValueFactories(); - if (valueType == PropertyType.STRING || valueType == PropertyType.BINARY) { - valueFactories.getNameFactory().create(value.getString()); - return true; - } - - if (valueType == PropertyType.PATH) { - Path path = valueFactories.getPathFactory().create(value.getString()); - - Segment[] segments = path.getSegmentsArray(); - return !path.isAbsolute() && segments.length == 1 && !segments[0].hasIndex(); - } - - return false; - - case PropertyType.PATH: - return value.getType() == PropertyType.STRING; - - // Nothing can be converted to these types (except themselves) - case PropertyType.REFERENCE: - case PropertyType.DOUBLE: - case PropertyType.LONG: - return false; - - // Anything can be converted to these types - case PropertyType.BINARY: - case PropertyType.STRING: - case PropertyType.UNDEFINED: - return true; - default: - assert false : "Unexpected JCR property type " + jcrPropertyType; - // This should still throw an exception even if assertions are turned off - throw new IllegalStateException("Invalid property type " + jcrPropertyType); - } - } catch (RepositoryException re) { + assert value instanceof JcrValue : "Illegal implementation of Value interface"; + ((JcrValue) value).asType(property.getRequiredType()); + } + catch (javax.jcr.ValueFormatException vfe) { + // Cast failed return false; - } catch (ValueFormatException vfe) { - return false; } + return true; } /** @@ -455,7 +366,12 @@ for (int i = 0; i < values.length; i++) { if (values[i] != null) { - if (!canCastValueToType(values[i], property.getRequiredType())) { + try { + assert values[i] instanceof JcrValue : "Illegal implementation of Value interface"; + ((JcrValue) values[i]).asType(property.getRequiredType()); + } + catch (javax.jcr.ValueFormatException vfe) { + // Cast failed return false; } } Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrValue.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrValue.java (revision 769) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrValue.java (working copy) @@ -25,13 +25,17 @@ import java.io.InputStream; import java.util.Calendar; +import javax.jcr.Node; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.Value; import javax.jcr.ValueFormatException; import net.jcip.annotations.NotThreadSafe; import org.jboss.dna.graph.property.Binary; +import org.jboss.dna.graph.property.Name; +import org.jboss.dna.graph.property.Path; import org.jboss.dna.graph.property.ValueFactories; +import org.jboss.dna.graph.property.Path.Segment; /** * @author jverhaeg @@ -62,6 +66,10 @@ return new ValueFormatException(JcrI18n.cannotConvertValue.text(value.getClass().getSimpleName(), type.getSimpleName())); } + ValueFormatException createValueFormatException( org.jboss.dna.graph.property.ValueFormatException vfe ) { + return new ValueFormatException(vfe); + } + /** * {@inheritDoc} * @@ -177,6 +185,112 @@ return type; } + /** + * Returns a copy of the current {@link JcrValue} cast to the JCR type specified by the type argument. If the + * value cannot be converted base don the JCR type conversion rules, a {@link ValueFormatException} will be thrown. + * + * @param type the JCR type from {@link PropertyType} that the new {@link JcrValue} should have. + * @return a new {@link JcrValue} with the given JCR type and an equivalent value. + * @throws ValueFormatException if the value contained by this {@link JcrValue} cannot be converted to the desired type. + * @see PropertyType + */ + JcrValue asType( int type ) throws ValueFormatException { + + if (type == this.type) { + return new JcrValue(this.valueFactories, this.type, this.value); + } + + switch (type) { + case PropertyType.BOOLEAN: + try { + if (this.type == PropertyType.STRING || this.type == PropertyType.BINARY) { + return new JcrValue(this.valueFactories, type, valueFactories.getBooleanFactory().create(value)); + } + } catch (org.jboss.dna.graph.property.ValueFormatException vfe) { + throw createValueFormatException(vfe); + } + throw createValueFormatException(boolean.class); + + case PropertyType.DATE: + try { + if (this.type == PropertyType.DOUBLE || this.type == PropertyType.LONG || this.type == PropertyType.STRING + || this.type == PropertyType.BINARY) { + return new JcrValue(this.valueFactories, type, valueFactories.getDateFactory().create(value)); + } + } catch (org.jboss.dna.graph.property.ValueFormatException vfe) { + throw createValueFormatException(vfe); + } + + throw createValueFormatException(Calendar.class); + + case PropertyType.NAME: + try { + if (this.type == PropertyType.STRING) { + return new JcrValue(this.valueFactories, type, this.valueFactories.getNameFactory().create(value)); + } + + String valueAsString = this.valueFactories.getStringFactory().create(value); + if (this.type == PropertyType.BINARY) { + return new JcrValue(this.valueFactories, type, this.valueFactories.getNameFactory().create(valueAsString)); + + } + + if (this.type == PropertyType.PATH) { + Path path = valueFactories.getPathFactory().create(valueAsString); + + Segment[] segments = path.getSegmentsArray(); + if (!path.isAbsolute() && segments.length == 1 && !segments[0].hasIndex()) { + return new JcrValue(this.valueFactories, type, + this.valueFactories.getNameFactory().create(valueAsString)); + + } + } + } catch (org.jboss.dna.graph.property.ValueFormatException vfe) { + throw createValueFormatException(vfe); + } + + throw createValueFormatException(Name.class); + + case PropertyType.PATH: + try { + if (this.type == PropertyType.STRING) { + return new JcrValue(this.valueFactories, type, this.valueFactories.getPathFactory().create(value)); + } + } catch (org.jboss.dna.graph.property.ValueFormatException vfe) { + throw createValueFormatException(vfe); + } + throw createValueFormatException(Path.class); + + // Nothing can be converted to these types (except themselves) + case PropertyType.REFERENCE: + throw createValueFormatException(Node.class); + case PropertyType.DOUBLE: + throw createValueFormatException(double.class); + case PropertyType.LONG: + throw createValueFormatException(long.class); + + // Anything can be converted to these types + case PropertyType.BINARY: + try { + return new JcrValue(this.valueFactories, type, valueFactories.getBinaryFactory().create(value)); + } catch (org.jboss.dna.graph.property.ValueFormatException vfe) { + throw createValueFormatException(vfe); + } + case PropertyType.STRING: + try { + return new JcrValue(this.valueFactories, type, valueFactories.getStringFactory().create(value)); + } catch (org.jboss.dna.graph.property.ValueFormatException vfe) { + throw createValueFormatException(vfe); + } + case PropertyType.UNDEFINED: + return new JcrValue(this.valueFactories, this.type, this.value); + default: + assert false : "Unexpected JCR property type " + type; + // This should still throw an exception even if assertions are turned off + throw new IllegalStateException("Invalid property type " + type); + } + } + void nonInputStreamConsumed() { if (state == State.INPUT_STREAM_CONSUMED) { throw new IllegalStateException(JcrI18n.inputStreamConsumed.text());