Index: jackrabbit-core/src/test/java/org/apache/jackrabbit/core/NodeImplTest.java =================================================================== --- jackrabbit-core/src/test/java/org/apache/jackrabbit/core/NodeImplTest.java (revision 1466852) +++ jackrabbit-core/src/test/java/org/apache/jackrabbit/core/NodeImplTest.java (working copy) @@ -397,4 +397,16 @@ root.remove(); session.save(); } + + public void testBracketsInNodeName() throws Exception { + final Node root = testRootNode.addNode("testBracketsInNodeName"); + + final String[] childNames = { "{A}", "B}", "{C", "(D)", "E)", "(F", }; + + for (String name : childNames) { + root.addNode(name); + root.getSession().save(); + assertTrue("Expecting child " + name + " to have been created", root.hasNode(name)); + } + } } Index: jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/conversion/PathParser.java =================================================================== --- jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/conversion/PathParser.java (revision 1466852) +++ jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/conversion/PathParser.java (working copy) @@ -47,7 +47,7 @@ /** * Parses jcrPath into a Path object using - * resolver to convert prefixes into namespace URI's. If + * resolver to convert prefixes into namespace URIs. If * resolver is null this method only checks the format of the * passed String and returns null. * @@ -66,7 +66,7 @@ /** * Parses jcrPath into a Path object using - * resolver to convert prefixes into namespace URI's. If the + * resolver to convert prefixes into namespace URIs. If the * specified jcrPath is an identifier based absolute path * beginning with an identifier segment the specified * IdentifierResolver will be used to resolve it to an @@ -94,7 +94,7 @@ /** * Parses jcrPath into a Path object using - * resolver to convert prefixes into namespace URI's. If the + * resolver to convert prefixes into namespace URIs. If the * specified jcrPath is an identifier based absolute path * beginning with an identifier segment the specified * IdentifierResolver will be used to resolve it to an @@ -132,7 +132,7 @@ * @param parent the parent path * @param jcrPath the JCR path * @param resolver the namespace resolver to get prefixes for namespace - * URI's. + * URIs. * @param factory * @return the Path object. * @throws MalformedPathException If the jcrPath is malformed. @@ -262,6 +262,10 @@ if (state == STATE_PREFIX_START && c != EOF) { throw new MalformedPathException("'" + jcrPath + "' is not a valid path. double slash '//' not allowed."); } + if (state == STATE_URI && c == EOF) { + // this handles the case where URI state was entered but the end of the segment was reached (JCR-3562) + state = STATE_URI_END; + } if (state == STATE_PREFIX || state == STATE_NAME || state == STATE_INDEX_END @@ -289,7 +293,7 @@ index = Path.INDEX_UNDEFINED; } else if (state == STATE_IDENTIFIER) { if (c == EOF) { - // eof identifier reached + // eof identifier reached if (jcrPath.charAt(pos - 2) != ']') { throw new MalformedPathException("'" + jcrPath + "' is not a valid path: Unterminated identifier segment."); } @@ -414,7 +418,7 @@ state = STATE_URI_END; } break; - + default: if (state == STATE_PREFIX_START || state == STATE_DOT || state == STATE_DOTDOT) { state = STATE_PREFIX;