![JAR search and dependency download from the Maven repository](/logo.png)
net.projectmonkey.internal.Errors Maven / Gradle / Ivy
/*
* Copyright 2011 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.projectmonkey.internal;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Formatter;
import java.util.List;
import net.projectmonkey.ConfigurationException;
import net.projectmonkey.MappingException;
import net.projectmonkey.TypeMap;
import net.projectmonkey.ValidationException;
import net.projectmonkey.internal.util.Types;
import net.projectmonkey.spi.ErrorMessage;
import net.projectmonkey.spi.PropertyInfo;
import net.projectmonkey.spi.PropertyMapping;
public final class Errors {
private List errors;
@SuppressWarnings("rawtypes")
private static final Converter>[] converters = new Converter[] {
new Converter(Class.class) {
public String toString(Class type) {
return type.getName();
}
}, new Converter(Member.class) {
public String toString(Member member) {
return Types.toString(member);
}
}, new Converter(PropertyInfo.class) {
public String toString(PropertyInfo propertyInfo) {
return Types.toString(propertyInfo.getMember());
}
}, new Converter(Collection.class) {
public String toString(Collection collection) {
StringBuilder builder = new StringBuilder();
boolean first = true;
for (Object o : collection) {
if (first)
first = false;
else
builder.append("\n");
builder.append("\t").append(Errors.convert(o));
}
return builder.toString();
}
} };
private static abstract class Converter {
final Class type;
Converter(Class type) {
this.type = type;
}
boolean appliesTo(Object subject) {
return type.isAssignableFrom(subject.getClass());
}
String convert(Object subject) {
return toString(type.cast(subject));
}
abstract String toString(T subject);
}
public Errors() {
}
/** Returns the formatted message for an exception with the specified messages. */
public static String format(String heading, Collection errorMessages) {
Formatter fmt = new Formatter().format(heading).format(":%n%n");
int index = 1;
boolean displayCauses = getOnlyCause(errorMessages) == null;
for (ErrorMessage errorMessage : errorMessages) {
fmt.format("%s) %s%n", index++, errorMessage.getMessage());
Throwable cause = errorMessage.getCause();
if (displayCauses && cause != null) {
StringWriter writer = new StringWriter();
cause.printStackTrace(new PrintWriter(writer));
fmt.format("Caused by: %s", writer.getBuffer());
}
fmt.format("%n");
}
if (errorMessages.size() == 1)
fmt.format("1 error");
else
fmt.format("%s errors", errorMessages.size());
return fmt.toString();
}
public static String format(String messageFormat, Object... arguments) {
for (int i = 0; i < arguments.length; i++)
arguments[i] = Errors.convert(arguments[i]);
return String.format(messageFormat, arguments);
}
/**
* Returns the cause throwable if there is exactly one cause in {@code messages}. If there are
* zero or multiple messages with causes, null is returned.
*/
public static Throwable getOnlyCause(Collection messages) {
Throwable onlyCause = null;
for (ErrorMessage message : messages) {
Throwable messageCause = message.getCause();
if (messageCause == null) {
continue;
}
if (onlyCause != null) {
return null;
}
onlyCause = messageCause;
}
return onlyCause;
}
private static Object convert(Object source) {
for (Converter> converter : converters)
if (converter.appliesTo(source))
return converter.convert(source);
return source;
}
public Errors addError(String message, Throwable throwable) {
return addMessage(throwable, "An error occured while %s", message);
}
public Errors addMessage(ErrorMessage message) {
if (errors == null)
errors = new ArrayList();
errors.add(message);
return this;
}
public Errors addMessage(String message, Object... arguments) {
return addMessage(null, message, arguments);
}
public Errors errorGettingValue(Member member, Throwable t) {
return addMessage(t, "Failed to get value from %s", member);
}
public Errors errorMapping(Object source, Class> destinationType) {
return addMessage("Error mapping %s to %s", source, Types.toString(destinationType));
}
public Errors errorMapping(Object source, Class> destinationType, Throwable t) {
return addMessage(t, "Error mapping %s to %s", source, Types.toString(destinationType));
}
public Errors errorSettingValue(Member member, Object value, Throwable t) {
return addMessage(t, "Failed to set value '%s' on %s", value, member);
}
public Errors errorTooLarge(Object source, Class> destinationType) {
return addMessage("Value '%s' is too large for %s", source, Types.toString(destinationType));
}
public Errors errorTooSmall(Object source, Class> destinationType) {
return addMessage("Value '%s' is too small for %s", source, Types.toString(destinationType));
}
public Errors errorUnmappedProperties(TypeMap, ?> typeMap, List unmappedProperties) {
return addMessage("Unmapped destination properties found in %s:\n\n%s", typeMap,
unmappedProperties);
}
public Errors errorCircularReference(Class> type) {
return addMessage("Circular reference detected in %s.", type);
}
public Errors errorUnsupportedMapping(Class> sourceType, Class> destinationType) {
return addMessage("Missing type map configuration or unsupported mapping for %s to %s.",
sourceType, destinationType);
}
public List getMessages() {
if (errors == null)
return Collections.emptyList();
return errors;
}
public boolean hasErrors() {
return errors != null;
}
public Errors merge(Collection errorMessages) {
for (ErrorMessage message : errorMessages)
addMessage(message);
return this;
}
public Errors merge(Errors errors) {
for (ErrorMessage message : errors.getMessages())
addMessage(message);
return this;
}
public void throwConfigurationExceptionIfErrorsExist() {
if (hasErrors())
throw new ConfigurationException(getMessages());
}
public void throwValidationExceptionIfErrorsExist() {
if (hasErrors())
throw new ValidationException(getMessages());
}
public ConfigurationException toConfigurationException() {
return new ConfigurationException(getMessages());
}
public ErrorsException toException() {
return new ErrorsException(this);
}
public MappingException toMappingException() {
return new MappingException(getMessages());
}
Errors ambiguousDestination(Mutator destinationMutator, List extends PropertyMapping> mappings) {
List sourcePropertyInfo = new ArrayList();
for (PropertyMapping mapping : mappings) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < mapping.getSourceProperties().size(); i++) {
PropertyInfo info = mapping.getSourceProperties().get(i);
if (i > 0)
builder.append("/");
builder.append(Types.toString(info.getMember()));
}
sourcePropertyInfo.add(builder.toString());
}
return addMessage(
"The destination property %s matches multiple source property hierarchies:\n\n%s",
destinationMutator, sourcePropertyInfo);
}
Errors duplicateMapping(PropertyInfo destinationProperty) {
return addMessage("A mapping already exists for %s.", destinationProperty);
}
Errors errorAccessingConfigure(Throwable t) {
return addMessage(t, "Failed to access PropertyMap.configure().");
}
Errors errorAccessingProperty(PropertyInfo propertyInfo) {
return addMessage("Failed to access %s.", propertyInfo);
}
Errors errorConverting(net.projectmonkey.Converter, ?> converter, Class> sourceType,
Class> destinationType, Throwable throwable) {
return addMessage(throwable, "Converter %s failed to convert %s to %s.", converter, sourceType,
destinationType);
}
Errors errorEnhancingClass(Class> type, Throwable t) {
return addMessage(t, "Failed to generate proxy class for %s", type);
}
Errors errorInstantiatingProxy(Class> type, Throwable t) {
return addMessage(
t,
"Failed to instantiate proxied instance of %s. Ensure that %s has a non-private no-argument constructor.",
type, type);
}
public Errors errorInstantiatingDestination(Class> type, Throwable t) {
return addMessage(
t,
"Failed to instantiate instance of destination %s. Ensure that %s has a non-private no-argument constructor.",
type, type);
}
Errors invalidDestinationMethod(Method method) {
return addMessage(
"Invalid destination method %s. Ensure that method has one parameter and returns void.",
method);
}
Errors invalidSourceMethod(Method method) {
return addMessage(
"Invalid source method %s. Ensure that method has zero parameters and does not return void.",
method);
}
Errors invocationAgainstFinalClassOrMethod() {
return addMessage("Cannot map to final type.");
}
Errors missingDestination() {
return addMessage("A mapping is missing a required destination method.");
}
Errors missingMutatorForAccessor(Method method) {
return addMessage("No corresponding mutator was found for %s.", method);
}
Errors missingSource() {
return addMessage("A mapping is missing a required source method.");
}
Errors sourceOutsideOfMap() {
return addMessage("'source' cannot be used outside of a map statement.");
}
void throwMappingExceptionIfErrorsExist() {
if (hasErrors())
throw new MappingException(getMessages());
}
private Errors addMessage(Throwable cause, String message, Object... arguments) {
addMessage(new ErrorMessage(format(message, arguments), cause));
return this;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy