diff --git a/org.springframework.core/src/main/java/org/springframework/core/GenericCollectionTypeResolver.java b/org.springframework.core/src/main/java/org/springframework/core/GenericCollectionTypeResolver.java
index e4d4ae33fb4..2e2c4b1d62d 100644
--- a/org.springframework.core/src/main/java/org/springframework/core/GenericCollectionTypeResolver.java
+++ b/org.springframework.core/src/main/java/org/springframework/core/GenericCollectionTypeResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-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.
@@ -75,7 +75,7 @@ public abstract class GenericCollectionTypeResolver {
* @return the generic type, or null if none
*/
public static Class> getCollectionFieldType(Field collectionField) {
- return getGenericFieldType(collectionField, Collection.class, 0, 1);
+ return getGenericFieldType(collectionField, Collection.class, 0, null, 1);
}
/**
@@ -87,7 +87,21 @@ public abstract class GenericCollectionTypeResolver {
* @return the generic type, or null if none
*/
public static Class> getCollectionFieldType(Field collectionField, int nestingLevel) {
- return getGenericFieldType(collectionField, Collection.class, 0, nestingLevel);
+ return getGenericFieldType(collectionField, Collection.class, 0, null, nestingLevel);
+ }
+
+ /**
+ * Determine the generic element type of the given Collection field.
+ * @param collectionField the collection field to introspect
+ * @param nestingLevel the nesting level of the target type
+ * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
+ * nested List, whereas 2 would indicate the element of the nested List)
+ * @param typeIndexesPerLevel Map keyed by nesting level, with each value
+ * expressing the type index for traversal at that level
+ * @return the generic type, or null if none
+ */
+ public static Class> getCollectionFieldType(Field collectionField, int nestingLevel, Map typeIndexesPerLevel) {
+ return getGenericFieldType(collectionField, Collection.class, 0, typeIndexesPerLevel, nestingLevel);
}
/**
@@ -96,7 +110,7 @@ public abstract class GenericCollectionTypeResolver {
* @return the generic type, or null if none
*/
public static Class> getMapKeyFieldType(Field mapField) {
- return getGenericFieldType(mapField, Map.class, 0, 1);
+ return getGenericFieldType(mapField, Map.class, 0, null, 1);
}
/**
@@ -108,7 +122,21 @@ public abstract class GenericCollectionTypeResolver {
* @return the generic type, or null if none
*/
public static Class> getMapKeyFieldType(Field mapField, int nestingLevel) {
- return getGenericFieldType(mapField, Map.class, 0, nestingLevel);
+ return getGenericFieldType(mapField, Map.class, 0, null, nestingLevel);
+ }
+
+ /**
+ * Determine the generic key type of the given Map field.
+ * @param mapField the map field to introspect
+ * @param nestingLevel the nesting level of the target type
+ * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
+ * nested List, whereas 2 would indicate the element of the nested List)
+ * @param typeIndexesPerLevel Map keyed by nesting level, with each value
+ * expressing the type index for traversal at that level
+ * @return the generic type, or null if none
+ */
+ public static Class> getMapKeyFieldType(Field mapField, int nestingLevel, Map typeIndexesPerLevel) {
+ return getGenericFieldType(mapField, Map.class, 0, typeIndexesPerLevel, nestingLevel);
}
/**
@@ -117,7 +145,7 @@ public abstract class GenericCollectionTypeResolver {
* @return the generic type, or null if none
*/
public static Class> getMapValueFieldType(Field mapField) {
- return getGenericFieldType(mapField, Map.class, 1, 1);
+ return getGenericFieldType(mapField, Map.class, 1, null, 1);
}
/**
@@ -129,7 +157,21 @@ public abstract class GenericCollectionTypeResolver {
* @return the generic type, or null if none
*/
public static Class> getMapValueFieldType(Field mapField, int nestingLevel) {
- return getGenericFieldType(mapField, Map.class, 1, nestingLevel);
+ return getGenericFieldType(mapField, Map.class, 1, null, nestingLevel);
+ }
+
+ /**
+ * Determine the generic value type of the given Map field.
+ * @param mapField the map field to introspect
+ * @param nestingLevel the nesting level of the target type
+ * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
+ * nested List, whereas 2 would indicate the element of the nested List)
+ * @param typeIndexesPerLevel Map keyed by nesting level, with each value
+ * expressing the type index for traversal at that level
+ * @return the generic type, or null if none
+ */
+ public static Class> getMapValueFieldType(Field mapField, int nestingLevel, Map typeIndexesPerLevel) {
+ return getGenericFieldType(mapField, Map.class, 1, typeIndexesPerLevel, nestingLevel);
}
/**
@@ -234,8 +276,8 @@ public abstract class GenericCollectionTypeResolver {
* @return the generic type, or null if none
*/
private static Class> getGenericParameterType(MethodParameter methodParam, Class> source, int typeIndex) {
- return extractType(methodParam, GenericTypeResolver.getTargetType(methodParam),
- source, typeIndex, methodParam.getNestingLevel(), 1);
+ return extractType(GenericTypeResolver.getTargetType(methodParam), source, typeIndex,
+ methodParam.typeVariableMap, methodParam.typeIndexesPerLevel, methodParam.getNestingLevel(), 1);
}
/**
@@ -247,8 +289,9 @@ public abstract class GenericCollectionTypeResolver {
* @param nestingLevel the nesting level of the target type
* @return the generic type, or null if none
*/
- private static Class> getGenericFieldType(Field field, Class> source, int typeIndex, int nestingLevel) {
- return extractType(null, field.getGenericType(), source, typeIndex, nestingLevel, 1);
+ private static Class> getGenericFieldType(Field field, Class> source, int typeIndex,
+ Map typeIndexesPerLevel, int nestingLevel) {
+ return extractType(field.getGenericType(), source, typeIndex, null, typeIndexesPerLevel, nestingLevel, 1);
}
/**
@@ -261,12 +304,11 @@ public abstract class GenericCollectionTypeResolver {
* @return the generic type, or null if none
*/
private static Class> getGenericReturnType(Method method, Class> source, int typeIndex, int nestingLevel) {
- return extractType(null, method.getGenericReturnType(), source, typeIndex, nestingLevel, 1);
+ return extractType(method.getGenericReturnType(), source, typeIndex, null, null, nestingLevel, 1);
}
/**
* Extract the generic type from the given Type object.
- * @param methodParam the method parameter specification
* @param type the Type to check
* @param source the source collection/map Class that we check
* @param typeIndex the index of the actual type argument
@@ -274,22 +316,28 @@ public abstract class GenericCollectionTypeResolver {
* @param currentLevel the current nested level
* @return the generic type as Class, or null if none
*/
- private static Class> extractType(
- MethodParameter methodParam, Type type, Class> source, int typeIndex, int nestingLevel, int currentLevel) {
+ private static Class> extractType(Type type, Class> source, int typeIndex,
+ Map typeVariableMap, Map typeIndexesPerLevel,
+ int nestingLevel, int currentLevel) {
Type resolvedType = type;
- if (type instanceof TypeVariable && methodParam != null && methodParam.typeVariableMap != null) {
- Type mappedType = methodParam.typeVariableMap.get((TypeVariable) type);
+ if (type instanceof TypeVariable && typeVariableMap != null) {
+ Type mappedType = typeVariableMap.get((TypeVariable) type);
if (mappedType != null) {
resolvedType = mappedType;
}
}
if (resolvedType instanceof ParameterizedType) {
- return extractTypeFromParameterizedType(
- methodParam, (ParameterizedType) resolvedType, source, typeIndex, nestingLevel, currentLevel);
+ return extractTypeFromParameterizedType((ParameterizedType) resolvedType, source, typeIndex, typeVariableMap, typeIndexesPerLevel,
+ nestingLevel, currentLevel);
}
else if (resolvedType instanceof Class) {
- return extractTypeFromClass(methodParam, (Class) resolvedType, source, typeIndex, nestingLevel, currentLevel);
+ return extractTypeFromClass((Class) resolvedType, source, typeIndex, typeVariableMap, typeIndexesPerLevel,
+ nestingLevel, currentLevel);
+ }
+ else if (resolvedType instanceof GenericArrayType) {
+ Type compType = ((GenericArrayType) resolvedType).getGenericComponentType();
+ return extractType(compType, source, typeIndex, typeVariableMap, typeIndexesPerLevel, nestingLevel, currentLevel + 1);
}
else {
return null;
@@ -298,7 +346,6 @@ public abstract class GenericCollectionTypeResolver {
/**
* Extract the generic type from the given ParameterizedType object.
- * @param methodParam the method parameter specification
* @param ptype the ParameterizedType to check
* @param source the expected raw source type (can be null)
* @param typeIndex the index of the actual type argument
@@ -306,8 +353,9 @@ public abstract class GenericCollectionTypeResolver {
* @param currentLevel the current nested level
* @return the generic type as Class, or null if none
*/
- private static Class> extractTypeFromParameterizedType(MethodParameter methodParam,
- ParameterizedType ptype, Class> source, int typeIndex, int nestingLevel, int currentLevel) {
+ private static Class> extractTypeFromParameterizedType(ParameterizedType ptype, Class> source, int typeIndex,
+ Map typeVariableMap, Map typeIndexesPerLevel,
+ int nestingLevel, int currentLevel) {
if (!(ptype.getRawType() instanceof Class)) {
return null;
@@ -316,17 +364,17 @@ public abstract class GenericCollectionTypeResolver {
Type[] paramTypes = ptype.getActualTypeArguments();
if (nestingLevel - currentLevel > 0) {
int nextLevel = currentLevel + 1;
- Integer currentTypeIndex = (methodParam != null ? methodParam.getTypeIndexForLevel(nextLevel) : null);
+ Integer currentTypeIndex = (typeIndexesPerLevel != null ? typeIndexesPerLevel.get(nextLevel) : null);
// Default is last parameter type: Collection element or Map value.
int indexToUse = (currentTypeIndex != null ? currentTypeIndex : paramTypes.length - 1);
Type paramType = paramTypes[indexToUse];
- return extractType(methodParam, paramType, source, typeIndex, nestingLevel, nextLevel);
+ return extractType(paramType, source, typeIndex, typeVariableMap, typeIndexesPerLevel, nestingLevel, nextLevel);
}
if (source != null && !source.isAssignableFrom(rawType)) {
return null;
}
- Class fromSuperclassOrInterface =
- extractTypeFromClass(methodParam, rawType, source, typeIndex, nestingLevel, currentLevel);
+ Class fromSuperclassOrInterface = extractTypeFromClass(rawType, source, typeIndex, typeVariableMap, typeIndexesPerLevel,
+ nestingLevel, currentLevel);
if (fromSuperclassOrInterface != null) {
return fromSuperclassOrInterface;
}
@@ -334,8 +382,8 @@ public abstract class GenericCollectionTypeResolver {
return null;
}
Type paramType = paramTypes[typeIndex];
- if (paramType instanceof TypeVariable && methodParam != null && methodParam.typeVariableMap != null) {
- Type mappedType = methodParam.typeVariableMap.get((TypeVariable) paramType);
+ if (paramType instanceof TypeVariable && typeVariableMap != null) {
+ Type mappedType = typeVariableMap.get((TypeVariable) paramType);
if (mappedType != null) {
paramType = mappedType;
}
@@ -378,12 +426,11 @@ public abstract class GenericCollectionTypeResolver {
* @return the generic type as Class, or null if none
*/
private static Class> extractTypeFromClass(Class> clazz, Class> source, int typeIndex) {
- return extractTypeFromClass(null, clazz, source, typeIndex, 1, 1);
+ return extractTypeFromClass(clazz, source, typeIndex, null, null, 1, 1);
}
/**
* Extract the generic type from the given Class object.
- * @param methodParam the method parameter specification
* @param clazz the Class to check
* @param source the expected raw source type (can be null)
* @param typeIndex the index of the actual type argument
@@ -391,14 +438,16 @@ public abstract class GenericCollectionTypeResolver {
* @param currentLevel the current nested level
* @return the generic type as Class, or null if none
*/
- private static Class> extractTypeFromClass(
- MethodParameter methodParam, Class> clazz, Class> source, int typeIndex, int nestingLevel, int currentLevel) {
+ private static Class> extractTypeFromClass(Class> clazz, Class> source, int typeIndex,
+ Map typeVariableMap, Map typeIndexesPerLevel,
+ int nestingLevel, int currentLevel) {
if (clazz.getName().startsWith("java.util.")) {
return null;
}
if (clazz.getSuperclass() != null && isIntrospectionCandidate(clazz.getSuperclass())) {
- return extractType(methodParam, clazz.getGenericSuperclass(), source, typeIndex, nestingLevel, currentLevel);
+ return extractType(clazz.getGenericSuperclass(), source, typeIndex, typeVariableMap, typeIndexesPerLevel,
+ nestingLevel, currentLevel);
}
Type[] ifcs = clazz.getGenericInterfaces();
if (ifcs != null) {
@@ -408,7 +457,7 @@ public abstract class GenericCollectionTypeResolver {
rawType = ((ParameterizedType) ifc).getRawType();
}
if (rawType instanceof Class && isIntrospectionCandidate((Class) rawType)) {
- return extractType(methodParam, ifc, source, typeIndex, nestingLevel, currentLevel);
+ return extractType(ifc, source, typeIndex, typeVariableMap, typeIndexesPerLevel, nestingLevel, currentLevel);
}
}
}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/MethodParameter.java b/org.springframework.core/src/main/java/org/springframework/core/MethodParameter.java
index 4bb24bdac4c..361bae7eedc 100644
--- a/org.springframework.core/src/main/java/org/springframework/core/MethodParameter.java
+++ b/org.springframework.core/src/main/java/org/springframework/core/MethodParameter.java
@@ -60,12 +60,11 @@ public class MethodParameter {
private int nestingLevel = 1;
/** Map from Integer level to Integer type index */
- private Map typeIndexesPerLevel;
+ Map typeIndexesPerLevel;
Map typeVariableMap;
- private int hash;
-
+ private int hash = 0;
/**
@@ -440,12 +439,13 @@ public class MethodParameter {
@Override
public int hashCode() {
- int result = hash;
+ int result = this.hash;
if (result == 0) {
result = getMember().hashCode();
- result = 31 * result + parameterIndex;
- hash = result;
+ result = 31 * result + this.parameterIndex;
+ this.hash = result;
}
return result;
}
+
}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/AbstractDescriptor.java b/org.springframework.core/src/main/java/org/springframework/core/convert/AbstractDescriptor.java
index 3a1c0cda114..023e8ca6d17 100644
--- a/org.springframework.core/src/main/java/org/springframework/core/convert/AbstractDescriptor.java
+++ b/org.springframework.core/src/main/java/org/springframework/core/convert/AbstractDescriptor.java
@@ -13,12 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.springframework.core.convert;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Map;
+/**
+ * @author Keith Donald
+ * @since 3.1
+ */
abstract class AbstractDescriptor {
private final Class> type;
@@ -37,11 +42,13 @@ abstract class AbstractDescriptor {
public TypeDescriptor getElementTypeDescriptor() {
if (isCollection()) {
Class> elementType = resolveCollectionElementType();
- return elementType != null ? new TypeDescriptor(nested(elementType, 0)) : null;
- } else if (isArray()) {
+ return (elementType != null ? new TypeDescriptor(nested(elementType, 0)) : null);
+ }
+ else if (isArray()) {
Class> elementType = getType().getComponentType();
return new TypeDescriptor(nested(elementType, 0));
- } else {
+ }
+ else {
return null;
}
}
@@ -50,7 +57,8 @@ abstract class AbstractDescriptor {
if (isMap()) {
Class> keyType = resolveMapKeyType();
return keyType != null ? new TypeDescriptor(nested(keyType, 0)) : null;
- } else {
+ }
+ else {
return null;
}
}
@@ -59,7 +67,8 @@ abstract class AbstractDescriptor {
if (isMap()) {
Class> valueType = resolveMapValueType();
return valueType != null ? new TypeDescriptor(nested(valueType, 1)) : null;
- } else {
+ }
+ else {
return null;
}
}
@@ -70,12 +79,15 @@ abstract class AbstractDescriptor {
if (isCollection()) {
Class> elementType = resolveCollectionElementType();
return elementType != null ? nested(elementType, 0) : null;
- } else if (isArray()) {
+ }
+ else if (isArray()) {
return nested(getType().getComponentType(), 0);
- } else if (isMap()) {
+ }
+ else if (isMap()) {
Class> mapValueType = resolveMapValueType();
return mapValueType != null ? nested(mapValueType, 1) : null;
- } else {
+ }
+ else {
throw new IllegalStateException("Not a collection, array, or map: cannot resolve nested value types");
}
}
@@ -104,4 +116,4 @@ abstract class AbstractDescriptor {
return Map.class.isAssignableFrom(getType());
}
-}
\ No newline at end of file
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/ClassDescriptor.java b/org.springframework.core/src/main/java/org/springframework/core/convert/ClassDescriptor.java
index aa40d92d1d6..527fced98bd 100644
--- a/org.springframework.core/src/main/java/org/springframework/core/convert/ClassDescriptor.java
+++ b/org.springframework.core/src/main/java/org/springframework/core/convert/ClassDescriptor.java
@@ -13,10 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.springframework.core.convert;
import java.lang.annotation.Annotation;
+/**
+ * @author Keith Donald
+ * @since 3.1
+ */
class ClassDescriptor extends AbstractDescriptor {
ClassDescriptor(Class> type) {
@@ -48,4 +53,4 @@ class ClassDescriptor extends AbstractDescriptor {
return new ClassDescriptor(type);
}
-}
\ No newline at end of file
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/FieldDescriptor.java b/org.springframework.core/src/main/java/org/springframework/core/convert/FieldDescriptor.java
index a03c561ebf2..653e494fd8f 100644
--- a/org.springframework.core/src/main/java/org/springframework/core/convert/FieldDescriptor.java
+++ b/org.springframework.core/src/main/java/org/springframework/core/convert/FieldDescriptor.java
@@ -13,23 +13,44 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.springframework.core.convert;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
import org.springframework.core.GenericCollectionTypeResolver;
+/**
+ * @author Keith Donald
+ * @since 3.1
+ */
class FieldDescriptor extends AbstractDescriptor {
private final Field field;
private final int nestingLevel;
+ private Map typeIndexesPerLevel;
+
+
public FieldDescriptor(Field field) {
- this(field.getType(), field, 1, 0);
+ super(field.getType());
+ this.field = field;
+ this.nestingLevel = 1;
}
+ private FieldDescriptor(Class> type, Field field, int nestingLevel, int typeIndex, Map typeIndexesPerLevel) {
+ super(type);
+ this.field = field;
+ this.nestingLevel = nestingLevel;
+ this.typeIndexesPerLevel = typeIndexesPerLevel;
+ this.typeIndexesPerLevel.put(nestingLevel, typeIndex);
+ }
+
+
@Override
public Annotation[] getAnnotations() {
return TypeDescriptor.nullSafeAnnotations(field.getAnnotations());
@@ -37,31 +58,25 @@ class FieldDescriptor extends AbstractDescriptor {
@Override
protected Class> resolveCollectionElementType() {
- return GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel);
+ return GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel, this.typeIndexesPerLevel);
}
@Override
protected Class> resolveMapKeyType() {
- return GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel);
+ return GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel, this.typeIndexesPerLevel);
}
@Override
protected Class> resolveMapValueType() {
- return GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel);
+ return GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel, this.typeIndexesPerLevel);
}
@Override
protected AbstractDescriptor nested(Class> type, int typeIndex) {
- return new FieldDescriptor(type, this.field, this.nestingLevel + 1, typeIndex);
- }
-
- // internal
-
- private FieldDescriptor(Class> type, Field field, int nestingLevel, int typeIndex) {
- super(type);
- this.field = field;
- this.nestingLevel = nestingLevel;
- // TODO typeIndex is not preserved at current nestingLevel is not preserved: see SPR-8394
+ if (this.typeIndexesPerLevel == null) {
+ this.typeIndexesPerLevel = new HashMap(4);
+ }
+ return new FieldDescriptor(type, this.field, this.nestingLevel + 1, typeIndex, this.typeIndexesPerLevel);
}
-}
\ No newline at end of file
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/ParameterDescriptor.java b/org.springframework.core/src/main/java/org/springframework/core/convert/ParameterDescriptor.java
index 93f12d181b5..5f0fa28174a 100644
--- a/org.springframework.core/src/main/java/org/springframework/core/convert/ParameterDescriptor.java
+++ b/org.springframework.core/src/main/java/org/springframework/core/convert/ParameterDescriptor.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.springframework.core.convert;
import java.lang.annotation.Annotation;
@@ -20,41 +21,52 @@ import java.lang.annotation.Annotation;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.MethodParameter;
+/**
+ * @author Keith Donald
+ * @since 3.1
+ */
class ParameterDescriptor extends AbstractDescriptor {
private final MethodParameter methodParameter;
+
public ParameterDescriptor(MethodParameter methodParameter) {
super(methodParameter.getParameterType());
if (methodParameter.getNestingLevel() != 1) {
- throw new IllegalArgumentException("The MethodParameter argument must have its nestingLevel set to 1");
+ throw new IllegalArgumentException("MethodParameter argument must have its nestingLevel set to 1");
}
this.methodParameter = methodParameter;
}
+ private ParameterDescriptor(Class> type, MethodParameter methodParameter) {
+ super(type);
+ this.methodParameter = methodParameter;
+ }
+
+
@Override
public Annotation[] getAnnotations() {
- if (methodParameter.getParameterIndex() == -1) {
- return TypeDescriptor.nullSafeAnnotations(methodParameter.getMethodAnnotations());
+ if (this.methodParameter.getParameterIndex() == -1) {
+ return TypeDescriptor.nullSafeAnnotations(this.methodParameter.getMethodAnnotations());
}
else {
- return TypeDescriptor.nullSafeAnnotations(methodParameter.getParameterAnnotations());
+ return TypeDescriptor.nullSafeAnnotations(this.methodParameter.getParameterAnnotations());
}
}
@Override
protected Class> resolveCollectionElementType() {
- return GenericCollectionTypeResolver.getCollectionParameterType(methodParameter);
+ return GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter);
}
@Override
protected Class> resolveMapKeyType() {
- return GenericCollectionTypeResolver.getMapKeyParameterType(methodParameter);
+ return GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter);
}
@Override
protected Class> resolveMapValueType() {
- return GenericCollectionTypeResolver.getMapValueParameterType(methodParameter);
+ return GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter);
}
@Override
@@ -65,11 +77,4 @@ class ParameterDescriptor extends AbstractDescriptor {
return new ParameterDescriptor(type, methodParameter);
}
- // internal
-
- private ParameterDescriptor(Class> type, MethodParameter methodParameter) {
- super(type);
- this.methodParameter = methodParameter;
- }
-
-}
\ No newline at end of file
+}