Did I do this right? I'm not sure on how to properly attribute Apache-licensed code, especially since Spring doesn't have a NOTICE.txt file or anything like it. I just took the @author tags from the TypeUtils class and attributed them in our NOTICE.txt file.
---------- Forwarded message ---------- From: <[email protected]> Date: 14 September 2014 18:27 Subject: [17/21] git commit: Add TypeUtil adapted from Spring Core. To: [email protected] Add TypeUtil adapted from Spring Core. Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/798c3a56 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/798c3a56 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/798c3a56 Branch: refs/heads/master Commit: 798c3a560c4703d0532f48b60d9a037f17e820a6 Parents: 1f7b97e Author: Matt Sicker <[email protected]> Authored: Sun Sep 14 16:51:52 2014 -0500 Committer: Matt Sicker <[email protected]> Committed: Sun Sep 14 16:51:52 2014 -0500 ---------------------------------------------------------------------- NOTICE.txt | 3 + .../logging/log4j/core/util/TypeUtil.java | 199 +++++++++++++++++++ 2 files changed, 202 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/798c3a56/NOTICE.txt ---------------------------------------------------------------------- diff --git a/NOTICE.txt b/NOTICE.txt index 2b81bc1..d59c783 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -9,3 +9,6 @@ Copyright 2005-2006 Tim Fennell Dumbster SMTP test server Copyright 2004 Jason Paul Kitchen + +TypeUtil.java +Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/798c3a56/log4j-core/src/main/java/org/apache/logging/log4j/core/util/TypeUtil.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/TypeUtil.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/TypeUtil.java new file mode 100644 index 0000000..060d1f8 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/TypeUtil.java @@ -0,0 +1,199 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.logging.log4j.core.util; + +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.WildcardType; + +/** + * Utility class for working with Java {@link Type}s and derivatives. This class is adapted heavily from the + * <a href="http://projects.spring.io/spring-framework/">Spring Framework</a>, specifically the + * <a href=" http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/util/TypeUtils.html ">TypeUtils</a> + * class. + * + * @see java.lang.reflect.Type + * @see java.lang.reflect.GenericArrayType + * @see java.lang.reflect.ParameterizedType + * @see java.lang.reflect.WildcardType + * @see java.lang.Class + * @since 2.1 + */ +public final class TypeUtil { + private TypeUtil() { + } + + /** + * Indicates if two {@link Type}s are assignment compatible. + * + * @param lhs the left hand side to check assignability to + * @param rhs the right hand side to check assignability from + * @return {@code true} if it is legal to assign a variable of type {@code rhs} to a variable of type {@code lhs} + * @see Class#isAssignableFrom(Class) + */ + public static boolean isAssignable(final Type lhs, final Type rhs) { + Assert.requireNonNull(lhs, "No left hand side type provided"); + Assert.requireNonNull(rhs, "No right hand side type provided"); + if (lhs.equals(rhs)) { + return true; + } + if (Object.class.equals(lhs)) { + // everything is assignable to Object + return true; + } + // raw type on left + if (lhs instanceof Class<?>) { + final Class<?> lhsClass = (Class<?>) lhs; + if (rhs instanceof Class<?>) { + // no generics involved + final Class<?> rhsClass = (Class<?>) rhs; + return lhsClass.isAssignableFrom(rhsClass); + } + if (rhs instanceof ParameterizedType) { + // check to see if the parameterized type has the same raw type as the lhs; this is legal + final Type rhsRawType = ((ParameterizedType) rhs).getRawType(); + if (rhsRawType instanceof Class<?>) { + return lhsClass.isAssignableFrom((Class<?>) rhsRawType); + } + } + if (lhsClass.isArray() && rhs instanceof GenericArrayType) { + // check for compatible array component types + return isAssignable(lhsClass.getComponentType(), ((GenericArrayType) rhs).getGenericComponentType()); + } + } + // parameterized type on left + if (lhs instanceof ParameterizedType) { + final ParameterizedType lhsType = (ParameterizedType) lhs; + if (rhs instanceof Class<?>) { + final Type lhsRawType = lhsType.getRawType(); + if (lhsRawType instanceof Class<?>) { + return ((Class<?>) lhsRawType).isAssignableFrom((Class<?>) rhs); + } + } else if (rhs instanceof ParameterizedType) { + final ParameterizedType rhsType = (ParameterizedType) rhs; + return isParameterizedAssignable(lhsType, rhsType); + } + } + // generic array type on left + if (lhs instanceof GenericArrayType) { + final Type lhsComponentType = ((GenericArrayType) lhs).getGenericComponentType(); + if (rhs instanceof Class<?>) { + // raw type on right + final Class<?> rhsClass = (Class<?>) rhs; + if (rhsClass.isArray()) { + return isAssignable(lhsComponentType, rhsClass.getComponentType()); + } + } else if (rhs instanceof GenericArrayType) { + return isAssignable(lhsComponentType, ((GenericArrayType) rhs).getGenericComponentType()); + } + } + // wildcard type on left + if (lhs instanceof WildcardType) { + return isWildcardAssignable((WildcardType) lhs, rhs); + } + // strange... + return false; + } + + private static boolean isParameterizedAssignable(final ParameterizedType lhs, final ParameterizedType rhs) { + if (lhs.equals(rhs)) { + // that was easy + return true; + } + final Type[] lhsTypeArguments = lhs.getActualTypeArguments(); + final Type[] rhsTypeArguments = rhs.getActualTypeArguments(); + final int size = lhsTypeArguments.length; + if (rhsTypeArguments.length != size) { + // clearly incompatible types + return false; + } + for (int i = 0; i < size; i++) { + // verify all type arguments are assignable + final Type lhsArgument = lhsTypeArguments[i]; + final Type rhsArgument = rhsTypeArguments[i]; + if (!lhsArgument.equals(rhsArgument) && + !(lhsArgument instanceof WildcardType && + isWildcardAssignable((WildcardType) lhsArgument, rhsArgument))) { + return false; + } + } + return true; + } + + private static boolean isWildcardAssignable(final WildcardType lhs, final Type rhs) { + final Type[] lhsUpperBounds = getEffectiveUpperBounds(lhs); + final Type[] lhsLowerBounds = getEffectiveLowerBounds(lhs); + if (rhs instanceof WildcardType) { + // oh boy, this scenario requires checking a lot of assignability! + final WildcardType rhsType = (WildcardType) rhs; + final Type[] rhsUpperBounds = getEffectiveUpperBounds(rhsType); + final Type[] rhsLowerBounds = getEffectiveLowerBounds(rhsType); + for (final Type lhsUpperBound : lhsUpperBounds) { + for (final Type rhsUpperBound : rhsUpperBounds) { + if (!isBoundAssignable(lhsUpperBound, rhsUpperBound)) { + return false; + } + } + for (final Type rhsLowerBound : rhsLowerBounds) { + if (!isBoundAssignable(lhsUpperBound, rhsLowerBound)) { + return false; + } + } + } + for (final Type lhsLowerBound : lhsLowerBounds) { + for (final Type rhsUpperBound : rhsUpperBounds) { + if (!isBoundAssignable(rhsUpperBound, lhsLowerBound)) { + return false; + } + } + for (final Type rhsLowerBound : rhsLowerBounds) { + if (!isBoundAssignable(rhsLowerBound, lhsLowerBound)) { + return false; + } + } + } + } else { + // phew, far less bounds to check + for (final Type lhsUpperBound : lhsUpperBounds) { + if (!isBoundAssignable(lhsUpperBound, rhs)) { + return false; + } + } + for (final Type lhsLowerBound : lhsLowerBounds) { + if (!isBoundAssignable(lhsLowerBound, rhs)) { + return false; + } + } + } + return true; + } + + private static Type[] getEffectiveUpperBounds(final WildcardType type) { + final Type[] upperBounds = type.getUpperBounds(); + return upperBounds.length == 0 ? new Type[]{Object.class} : upperBounds; + } + + private static Type[] getEffectiveLowerBounds(final WildcardType type) { + final Type[] lowerBounds = type.getLowerBounds(); + return lowerBounds.length == 0 ? new Type[]{null} : lowerBounds; + } + + private static boolean isBoundAssignable(final Type lhs, final Type rhs) { + return (rhs == null) || ((lhs != null) && isAssignable(lhs, rhs)); + } +} -- Matt Sicker <[email protected]>
