Skip to content

Commit 9fe29dc

Browse files
authored
perf: probing access without exception, cache MethodHandles (#66)
* perf: skip while without predicate to allow inline * perf: cache default method handles * perf: cache used MethodHandles * test: adds unit tests
1 parent 0fbc271 commit 9fe29dc

File tree

4 files changed

+313
-163
lines changed

4 files changed

+313
-163
lines changed

src/main/java/org/hisp/dhis/jsontree/JsonNode.java

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
*/
2828
package org.hisp.dhis.jsontree;
2929

30+
import org.hisp.dhis.jsontree.internal.Maybe;
3031
import org.hisp.dhis.jsontree.internal.Surly;
3132

3233
import java.io.IOException;
@@ -250,42 +251,56 @@ default JsonNode getParent() {
250251
* @throws JsonPathException when no such node exists in the subtree of this node
251252
*/
252253
@Surly
253-
default JsonNode get(@Surly String path )
254-
throws JsonPathException {
254+
default JsonNode get(@Surly String path ) throws JsonPathException {
255255
if ( path.isEmpty() ) return this;
256256
if ( "$".equals( path ) ) return getRoot();
257-
if ( path.startsWith( "$" ) ) return getRoot().get( path.substring( 1 ) );
258-
if (!path.startsWith( "{" ) && !path.startsWith( "[" ) && !path.startsWith( "." ))
259-
path = "."+path;
257+
char c0 = path.charAt( 0 );
258+
if ( c0 == '$' ) return getRoot().get( path.substring( 1 ) );
259+
if ( c0 != '{' && c0 != '[' && c0 != '.' ) path = "."+path;
260260
return get( JsonPath.of( path ) );
261261
}
262262

263263
/**
264+
* Access the node at the given path in the subtree of this node.
264265
*
266+
* @param path a simple or nested path relative to this node. A path starting with {@code $} is relative to the root
267+
* node of this node, in other words it is an absolute path
268+
* @return the node at the given path or {@code null} if no such node exists
269+
* @throws JsonPathException when the provided path is malformed
270+
* @since 1.5
271+
*/
272+
@Maybe
273+
default JsonNode getOrNull(@Surly String path ) throws JsonPathException {
274+
if ( path.isEmpty() ) return this;
275+
if ( "$".equals( path ) ) return getRoot();
276+
char c0 = path.charAt( 0 );
277+
if ( c0 == '$' ) return getRoot().getOrNull( path.substring( 1 ) );
278+
if ( c0 != '{' && c0 != '[' && c0 != '.' ) path = "."+path;
279+
return getOrNull( JsonPath.of( path ) );
280+
}
281+
282+
/**
265283
* @param path a path understood relative to this node's {@link #getPath()}
266284
* @return the node at the given path
285+
* @throws JsonPathException when no such node exists in the subtree of this node
267286
* @since 1.1
268287
*/
269288
@Surly
270-
default JsonNode get(@Surly JsonPath path) {
289+
default JsonNode get(@Surly JsonPath path) throws JsonPathException {
271290
throw new JsonPathException( path,
272291
format( "This is a leaf node of type %s that does not have any children at path: %s", getType(), path ) );
273292
}
274293

275294
/**
276-
* Access node by path with default.
277-
*
278-
* @param path a simple or nested path relative to this node
279-
* @param orDefault value to return in no node at the given path exist in this subtree
280-
* @return the node at path or the provided default if no such node exists
281-
* @since 1.1
295+
* @param path a path understood relative to this node's {@link #getPath()}
296+
* @return the node at the given path or {@code null} if no such node exists
297+
* @throws JsonPathException when the provided path is malformed
298+
* @since 1.5
282299
*/
283-
default JsonNode getOrDefault( String path, JsonNode orDefault ) {
284-
try {
285-
return get( path );
286-
} catch ( JsonPathException ex ) {
287-
return orDefault;
288-
}
300+
@Maybe
301+
default JsonNode getOrNull(@Surly JsonPath path) throws JsonPathException {
302+
throw new JsonPathException( path,
303+
format( "This is a leaf node of type %s that does not have any children at path: %s", getType(), path ) );
289304
}
290305

291306
/**
@@ -332,7 +347,7 @@ default boolean isRoot() {
332347
*/
333348
default boolean isMember( String name ) {
334349
try {
335-
return member( name ) != null;
350+
return memberOrNull( name ) != null;
336351
} catch ( JsonPathException ex ) {
337352
return false;
338353
}
@@ -347,7 +362,7 @@ default boolean isMember( String name ) {
347362
*/
348363
default boolean isElement( int index ) {
349364
try {
350-
return element( index ) != null;
365+
return elementOrNull( index ) != null;
351366
} catch ( JsonPathException ex ) {
352367
return false;
353368
}
@@ -379,11 +394,27 @@ default boolean isElement( int index ) {
379394
* @throws JsonPathException when no such member exists
380395
* @throws JsonTreeException if this node is not an object node that could have members
381396
*/
397+
@Surly
382398
default JsonNode member( String name )
383399
throws JsonPathException {
384400
throw new JsonTreeException( getType() + " node has no member property: " + name );
385401
}
386402

403+
/**
404+
* OBS! Only defined when this node is of type {@link JsonNodeType#OBJECT}).
405+
*
406+
* @param name name of the member to access
407+
* @return the member with the given name or {@code null} if no such member exists
408+
* @throws JsonPathException when the path is malformed
409+
* @throws JsonTreeException if this node is not an object node that could have members
410+
* @since 1.5
411+
*/
412+
@Maybe
413+
default JsonNode memberOrNull( String name )
414+
throws JsonPathException {
415+
throw new JsonTreeException( getType() + " node has no member property: " + name );
416+
}
417+
387418
/**
388419
* OBS! Only defined when this node is of type {@link JsonNodeType#OBJECT}).
389420
* <p>
@@ -463,11 +494,27 @@ default Iterator<Entry<String, JsonNode>> members( boolean cacheNodes ) {
463494
* @throws JsonPathException when no such element exists
464495
* @throws JsonTreeException if this node is not an array node that could have elements
465496
*/
497+
@Surly
466498
default JsonNode element( int index )
467499
throws JsonPathException {
468500
throw new JsonTreeException( getType() + " node has no element property for index: " + index );
469501
}
470502

503+
/**
504+
* OBS! Only defined when this node is of type {@link JsonNodeType#ARRAY}).
505+
*
506+
* @param index index of the element to access
507+
* @return the node at the given array index or {@code null} if no such element exists
508+
* @throws JsonPathException when the index is negative (invalid)
509+
* @throws JsonTreeException if this node is not an array node that could have elements
510+
* @since 1.5
511+
*/
512+
@Maybe
513+
default JsonNode elementOrNull( int index )
514+
throws JsonPathException {
515+
throw new JsonTreeException( getType() + " node has no element property for index: " + index );
516+
}
517+
471518
/**
472519
* OBS! Only defined when this node is of type {@link JsonNodeType#ARRAY}).
473520
* <p>

0 commit comments

Comments
 (0)