You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-dev@logging.apache.org by Matt Sicker <bo...@gmail.com> on 2014/09/15 01:40:16 UTC

Fwd: [17/21] git commit: Add TypeUtil adapted from Spring Core.

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: <ma...@apache.org>
Date: 14 September 2014 18:27
Subject: [17/21] git commit: Add TypeUtil adapted from Spring Core.
To: commits@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 <ma...@apache.org>
Authored: Sun Sep 14 16:51:52 2014 -0500
Committer: Matt Sicker <ma...@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 <bo...@gmail.com>