diff --git a/src/main/java/org/springframework/data/mapping/PropertyPath.java b/src/main/java/org/springframework/data/mapping/PropertyPath.java index c98662542..79d133d8c 100644 --- a/src/main/java/org/springframework/data/mapping/PropertyPath.java +++ b/src/main/java/org/springframework/data/mapping/PropertyPath.java @@ -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 { * @param owningType must not be {@literal null}. * @param base the {@link PropertyPath} previously found. */ - PropertyPath(String name, TypeInformation owningType, Stack base) { + PropertyPath(String name, TypeInformation owningType, List base) { Assert.hasText(name); Assert.notNull(owningType); @@ -303,7 +303,7 @@ public class PropertyPath implements Iterable { * @param type * @return */ - private static PropertyPath create(String source, TypeInformation type, Stack base) { + private static PropertyPath create(String source, TypeInformation type, List base) { return create(source, type, "", base); } @@ -317,7 +317,7 @@ public class PropertyPath implements Iterable { * @param addTail * @return */ - private static PropertyPath create(String source, TypeInformation type, String addTail, Stack base) { + private static PropertyPath create(String source, TypeInformation type, String addTail, List base) { PropertyReferenceException exception = null; PropertyPath current = null; @@ -327,13 +327,14 @@ public class PropertyPath implements Iterable { current = new PropertyPath(source, type, base); if (!base.isEmpty()) { - base.peek().next = current; + base.get(base.size() - 1).next = current; } - base.push(current); + List newBase = new ArrayList(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 { 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; diff --git a/src/main/java/org/springframework/data/mapping/PropertyReferenceException.java b/src/main/java/org/springframework/data/mapping/PropertyReferenceException.java index 90ba20158..dc074f624 100644 --- a/src/main/java/org/springframework/data/mapping/PropertyReferenceException.java +++ b/src/main/java/org/springframework/data/mapping/PropertyReferenceException.java @@ -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 base; + private final List 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 base) { + public PropertyReferenceException(String propertyName, TypeInformation type, List 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(); } } diff --git a/src/test/java/org/springframework/data/mapping/PropertyPathUnitTests.java b/src/test/java/org/springframework/data/mapping/PropertyPathUnitTests.java index aefe1d05a..328b04a75 100644 --- a/src/test/java/org/springframework/data/mapping/PropertyPathUnitTests.java +++ b/src/test/java/org/springframework/data/mapping/PropertyPathUnitTests.java @@ -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. @@ -310,6 +310,7 @@ public class PropertyPathUnitTests { /** * @see DATACMNS-381 */ + @Test public void exposesPreviouslyReferencedPathInExceptionMessage() { exception.expect(PropertyReferenceException.class); @@ -352,6 +353,26 @@ public class PropertyPathUnitTests { from("foo", (TypeInformation) null); } + @Test + public void returnsCompletePathIfResolutionFailedCompletely() { + + exception.expect(PropertyReferenceException.class); + exception.expectMessage("somethingDifferent"); + + from("somethingDifferent", Foo.class); + } + + @Test + public void foobar() { + + exception.expect(PropertyReferenceException.class); + exception.expectMessage("fooName"); + exception.expectMessage(FooBar.class.getSimpleName()); + exception.expectMessage("Bar.user"); + + from("userFooName", Bar.class); + } + private class Foo { String userName;