Browse Source

DATACMNS-283 - MappingInstantiationException captures more context now.

If an exception occurs in ReflectionEntityInstantiator we now capture more context about the failed instantiation.
pull/25/head
Oliver Gierke 13 years ago
parent
commit
0aef8c60b7
  1. 5
      src/main/java/org/springframework/data/convert/ReflectionEntityInstantiator.java
  2. 97
      src/main/java/org/springframework/data/mapping/model/MappingInstantiationException.java
  3. 54
      src/test/java/org/springframework/data/convert/ReflectionEntityInstantiatorUnitTests.java

5
src/main/java/org/springframework/data/convert/ReflectionEntityInstantiator.java

@ -17,6 +17,7 @@ package org.springframework.data.convert; @@ -17,6 +17,7 @@ package org.springframework.data.convert;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.BeanInstantiationException;
@ -60,7 +61,7 @@ public enum ReflectionEntityInstantiator implements EntityInstantiator { @@ -60,7 +61,7 @@ public enum ReflectionEntityInstantiator implements EntityInstantiator {
return BeanUtils.instantiateClass(entity.getType());
}
} catch (BeanInstantiationException e) {
throw new MappingInstantiationException(e.getMessage(), e);
new MappingInstantiationException(entity, Collections.emptyList(), e);
}
}
@ -74,7 +75,7 @@ public enum ReflectionEntityInstantiator implements EntityInstantiator { @@ -74,7 +75,7 @@ public enum ReflectionEntityInstantiator implements EntityInstantiator {
try {
return BeanUtils.instantiateClass(constructor.getConstructor(), params.toArray());
} catch (BeanInstantiationException e) {
throw new MappingInstantiationException(e.getMessage(), e);
throw new MappingInstantiationException(entity, params, e);
}
}
}

97
src/main/java/org/springframework/data/mapping/model/MappingInstantiationException.java

@ -1,11 +1,11 @@ @@ -1,11 +1,11 @@
/*
* Copyright (c) 2011 by the original author(s).
* Copyright 2011-2013 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@ -13,21 +13,102 @@ @@ -13,21 +13,102 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mapping.model;
import java.lang.reflect.Constructor;
import java.util.List;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PreferredConstructor;
import org.springframework.util.StringUtils;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
* Exception being thrown in case an entity could not be instantiated in the process of a to-object-mapping.
*
* @author Oliver Gierke
* @author Jon Brisbin
*/
public class MappingInstantiationException extends RuntimeException {
private static final long serialVersionUID = 822211065035487628L;
private static final String TEXT_TEMPLATE = "Failed to instantiate %s using constructor %s with arguments %s";
private final Class<?> entityType;
private final Constructor<?> constructor;
private final List<Object> constructorArguments;
/**
* Creates a {@link MappingInstantiationException} using the given message and cause.
*
* @deprecated use {@link #MappingInstantiationException(PersistentEntity, List, String, Exception)} instead.
* @param message
* @param cause
*/
@Deprecated
public MappingInstantiationException(String message, Exception cause) {
this(null, null, message, cause);
}
/**
* Creates a new {@link MappingInstantiationException} for the given {@link PersistentEntity}, constructor arguments
* and the causing exception.
*
* @param entity
* @param arguments
* @param cause
*/
public MappingInstantiationException(PersistentEntity<?, ?> entity, List<Object> arguments, Exception cause) {
this(entity, arguments, null, cause);
}
private MappingInstantiationException(PersistentEntity<?, ?> entity, List<Object> arguments, String message,
Exception cause) {
super(buildExceptionMessage(entity, arguments, null), cause);
this.entityType = entity == null ? null : entity.getType();
this.constructor = entity == null || entity.getPersistenceConstructor() == null ? null : entity
.getPersistenceConstructor().getConstructor();
this.constructorArguments = arguments;
}
private static final String buildExceptionMessage(PersistentEntity<?, ?> entity, List<Object> arguments,
String defaultMessage) {
if (entity == null) {
return defaultMessage;
}
PreferredConstructor<?, ?> constructor = entity.getPersistenceConstructor();
return String.format(TEXT_TEMPLATE, entity.getType().getName(), constructor == null ? "NO_CONSTRUCTOR"
: constructor.getConstructor().toString(), StringUtils.collectionToCommaDelimitedString(arguments));
}
/**
*
* Returns the type of the entity that was attempted to instantiate.
*
* @return the entityType
*/
private static final long serialVersionUID = 1L;
public Class<?> getEntityType() {
return entityType;
}
public MappingInstantiationException(String s, Throwable throwable) {
super(s, throwable);
/**
* The constructor used during the instantiation attempt.
*
* @return the constructor
*/
public Constructor<?> getConstructor() {
return constructor;
}
/**
* The constructor arguments used to invoke the constructor.
*
* @return the constructorArguments
*/
public List<Object> getConstructorArguments() {
return constructorArguments;
}
}

54
src/test/java/org/springframework/data/convert/ReflectionEntityInstantiatorUnitTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2012 the original author or authors.
* Copyright 2012-2013 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.
@ -19,12 +19,17 @@ import static org.hamcrest.Matchers.*; @@ -19,12 +19,17 @@ import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.springframework.data.convert.ReflectionEntityInstantiator.*;
import static org.springframework.data.util.ClassTypeInformation.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.convert.ReflectionEntityInstantiatorUnitTests.Outer.Inner;
import org.springframework.data.mapping.PersistentEntity;
@ -32,9 +37,9 @@ import org.springframework.data.mapping.PersistentProperty; @@ -32,9 +37,9 @@ import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.PreferredConstructor;
import org.springframework.data.mapping.PreferredConstructor.Parameter;
import org.springframework.data.mapping.model.BasicPersistentEntity;
import org.springframework.data.mapping.model.MappingInstantiationException;
import org.springframework.data.mapping.model.ParameterValueProvider;
import org.springframework.data.mapping.model.PreferredConstructorDiscoverer;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.FieldCallback;
@ -92,7 +97,7 @@ public class ReflectionEntityInstantiatorUnitTests<P extends PersistentProperty< @@ -92,7 +97,7 @@ public class ReflectionEntityInstantiatorUnitTests<P extends PersistentProperty<
@Test
public void createsInnerClassInstanceCorrectly() {
BasicPersistentEntity<Inner, P> entity = new BasicPersistentEntity<Inner, P>(ClassTypeInformation.from(Inner.class));
BasicPersistentEntity<Inner, P> entity = new BasicPersistentEntity<Inner, P>(from(Inner.class));
PreferredConstructor<Inner, P> constructor = entity.getPersistenceConstructor();
Parameter<Object, P> parameter = constructor.getParameters().iterator().next();
@ -114,6 +119,37 @@ public class ReflectionEntityInstantiatorUnitTests<P extends PersistentProperty< @@ -114,6 +119,37 @@ public class ReflectionEntityInstantiatorUnitTests<P extends PersistentProperty<
});
}
/**
* @see DATACMNS-283
*/
@Test
@SuppressWarnings({ "unchecked", "rawtypes" })
public void capturesContextOnInstantiationException() throws Exception {
PersistentEntity<Sample, P> entity = new BasicPersistentEntity<Sample, P>(from(Sample.class));
when(provider.getParameterValue(Mockito.any(Parameter.class))).thenReturn("FOO");
Constructor constructor = Sample.class.getConstructor(Long.class, String.class);
List<Object> parameters = Arrays.asList((Object) "FOO", (Object) "FOO");
try {
INSTANCE.createInstance(entity, provider);
fail("Expected MappingInstantiationException!");
} catch (MappingInstantiationException o_O) {
assertThat(o_O.getConstructor(), is(constructor));
assertThat(o_O.getConstructorArguments(), is(parameters));
assertEquals(Sample.class, o_O.getEntityType());
assertThat(o_O.getMessage(), containsString(Sample.class.getName()));
assertThat(o_O.getMessage(), containsString(Long.class.getName()));
assertThat(o_O.getMessage(), containsString(String.class.getName()));
assertThat(o_O.getMessage(), containsString("FOO"));
System.out.println(o_O.getMessage());
}
}
static class Foo {
Foo(String foo) {
@ -127,4 +163,16 @@ public class ReflectionEntityInstantiatorUnitTests<P extends PersistentProperty< @@ -127,4 +163,16 @@ public class ReflectionEntityInstantiatorUnitTests<P extends PersistentProperty<
}
}
static class Sample {
final Long id;
final String name;
public Sample(Long id, String name) {
this.id = id;
this.name = name;
}
}
}

Loading…
Cancel
Save