DATACMNS-546 - PropertyPath has better exception messages now.

PropertyPath now exposes the complete property named the resolution failed for in case it can't resolve a source String. It will expose the part of the Path from the deepest successful resolution result.

Changed the resolution algorithm to use a List instead of a Stack and a fresh instance of the former so that the nested recursion steps keep track of the correct resolution depths.
This commit is contained in:
Oliver Gierke
2014-07-21 18:04:29 +02:00
parent 5bc89af4e7
commit ba70380555
3 changed files with 55 additions and 18 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 the original author or authors.
* Copyright 2011-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -63,7 +63,7 @@ public class PropertyPath implements Iterable<PropertyPath> {
* @param owningType must not be {@literal null}.
* @param base the {@link PropertyPath} previously found.
*/
PropertyPath(String name, TypeInformation<?> owningType, Stack<PropertyPath> base) {
PropertyPath(String name, TypeInformation<?> owningType, List<PropertyPath> base) {
Assert.hasText(name);
Assert.notNull(owningType);
@@ -303,7 +303,7 @@ public class PropertyPath implements Iterable<PropertyPath> {
* @param type
* @return
*/
private static PropertyPath create(String source, TypeInformation<?> type, Stack<PropertyPath> base) {
private static PropertyPath create(String source, TypeInformation<?> type, List<PropertyPath> base) {
return create(source, type, "", base);
}
@@ -317,7 +317,7 @@ public class PropertyPath implements Iterable<PropertyPath> {
* @param addTail
* @return
*/
private static PropertyPath create(String source, TypeInformation<?> type, String addTail, Stack<PropertyPath> base) {
private static PropertyPath create(String source, TypeInformation<?> type, String addTail, List<PropertyPath> base) {
PropertyReferenceException exception = null;
PropertyPath current = null;
@@ -327,13 +327,14 @@ public class PropertyPath implements Iterable<PropertyPath> {
current = new PropertyPath(source, type, base);
if (!base.isEmpty()) {
base.peek().next = current;
base.get(base.size() - 1).next = current;
}
base.push(current);
List<PropertyPath> newBase = new ArrayList<PropertyPath>(base);
newBase.add(current);
if (StringUtils.hasText(addTail)) {
current.next = create(addTail, current.type, base);
current.next = create(addTail, current.type, newBase);
}
return current;
@@ -356,7 +357,11 @@ public class PropertyPath implements Iterable<PropertyPath> {
String head = source.substring(0, position);
String tail = source.substring(position);
return create(head, type, tail + addTail, base);
try {
return create(head, type, tail + addTail, base);
} catch (PropertyReferenceException e) {
throw e.hasDeeperResolutionDepthThan(exception) ? e : exception;
}
}
throw exception;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012 the original author or authors.
* Copyright 2012-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
*/
package org.springframework.data.mapping;
import java.util.Stack;
import java.util.List;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
@@ -32,23 +32,23 @@ public class PropertyReferenceException extends RuntimeException {
private final String propertyName;
private final TypeInformation<?> type;
private final Stack<PropertyPath> base;
private final List<PropertyPath> alreadyResolvedPath;
/**
* Creates a new {@link PropertyReferenceException}.
*
* @param propertyName the name of the property not found on the given type.
* @param type the type the property could not be found on.
* @param base the previously calculated {@link PropertyPath}s.
* @param alreadyResolvedPah the previously calculated {@link PropertyPath}s.
*/
public PropertyReferenceException(String propertyName, TypeInformation<?> type, Stack<PropertyPath> base) {
public PropertyReferenceException(String propertyName, TypeInformation<?> type, List<PropertyPath> alreadyResolvedPah) {
Assert.hasText(propertyName);
Assert.notNull(type);
this.propertyName = propertyName;
this.type = type;
this.base = base;
this.alreadyResolvedPath = alreadyResolvedPah;
}
/**
@@ -79,8 +79,8 @@ public class PropertyReferenceException extends RuntimeException {
StringBuilder builder = new StringBuilder(String.format(ERROR_TEMPLATE, propertyName, type.getType()
.getSimpleName()));
if (!base.isEmpty()) {
builder.append(" Traversed path: ").append(base.get(0).toString()).append(".");
if (!alreadyResolvedPath.isEmpty()) {
builder.append(" Traversed path: ").append(alreadyResolvedPath.get(0).toString()).append(".");
}
return builder.toString();
@@ -92,6 +92,17 @@ public class PropertyReferenceException extends RuntimeException {
* @return
*/
public PropertyPath getBaseProperty() {
return base.isEmpty() ? null : base.peek();
return alreadyResolvedPath.isEmpty() ? null : alreadyResolvedPath.get(alreadyResolvedPath.size() - 1);
}
/**
* Returns whether the given {@link PropertyReferenceException} has a deeper resolution depth (i.e. a longer path of
* already resolved properties) than the current exception.
*
* @param exception
* @return
*/
public boolean hasDeeperResolutionDepthThan(PropertyReferenceException exception) {
return this.alreadyResolvedPath.size() > exception.alreadyResolvedPath.size();
}
}