Discussion:
[17/21] git commit: Add TypeUtil adapted from Spring Core.
Matt Sicker
2014-09-14 23:40:16 UTC
Permalink
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: <***@apache.org>
Date: 14 September 2014 18:27
Subject: [17/21] git commit: Add TypeUtil adapted from Spring Core.
To: ***@logging.apache.org


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 <***@apache.org>
Authored: Sun Sep 14 16:51:52 2014 -0500
Committer: Matt Sicker <***@apache.org>
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 <***@gmail.com>
Loading...