From a49382809b1ac58ae1579e04a9b186e16c7a71f2 Mon Sep 17 00:00:00 2001 From: ddddyyyy <2115601599@qq.com> Date: Sat, 15 Aug 2020 20:15:42 +0800 Subject: [PATCH] [SHIRO-767] Fixed issue where org.apache.shiro.util.ClassUtil cannot load the array of Primitive DataType when use undertown as web container Use Class.forName instead of cl.loadClass(). Support for getting primitive data type by a static map. --- .../apache/shiro/lang/util/ClassUtils.java | 28 +++++- .../shiro/lang/util/ClassUtilsTest.java | 88 +++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 lang/src/test/java/org/apache/shiro/lang/util/ClassUtilsTest.java diff --git a/lang/src/main/java/org/apache/shiro/lang/util/ClassUtils.java b/lang/src/main/java/org/apache/shiro/lang/util/ClassUtils.java index ac885a1d27..dfefacf4c2 100644 --- a/lang/src/main/java/org/apache/shiro/lang/util/ClassUtils.java +++ b/lang/src/main/java/org/apache/shiro/lang/util/ClassUtils.java @@ -26,6 +26,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; @@ -44,6 +45,25 @@ public class ClassUtils { */ private static final Logger log = LoggerFactory.getLogger(ClassUtils.class); + + /** + * SHIRO-767: add a map to mapping primitive data type + */ + private static final HashMap> primClasses + = new HashMap<>(8, 1.0F); + static { + primClasses.put("boolean", boolean.class); + primClasses.put("byte", byte.class); + primClasses.put("char", char.class); + primClasses.put("short", short.class); + primClasses.put("int", int.class); + primClasses.put("long", long.class); + primClasses.put("float", float.class); + primClasses.put("double", double.class); + primClasses.put("void", void.class); + } + + /** * @since 1.0 */ @@ -146,6 +166,11 @@ public static Class forName(String fqcn) throws UnknownClassException { clazz = SYSTEM_CL_ACCESSOR.loadClass(fqcn); } + if (clazz == null) { + //SHIRO-767: support for getting primitive data type,such as int,double... + clazz = primClasses.get(fqcn); + } + if (clazz == null) { String msg = "Unable to load class named [" + fqcn + "] from the thread context, current, or " + "system/application ClassLoaders. All heuristics have been exhausted. Class could not be found."; @@ -252,7 +277,8 @@ public Class loadClass(String fqcn) { ClassLoader cl = getClassLoader(); if (cl != null) { try { - clazz = cl.loadClass(fqcn); + //SHIRO-767: Use Class.forName instead of cl.loadClass(), as byte arrays would fail otherwise. + clazz = Class.forName(fqcn, false, cl); } catch (ClassNotFoundException e) { if (log.isTraceEnabled()) { log.trace("Unable to load clazz named [" + fqcn + "] from class loader [" + cl + "]"); diff --git a/lang/src/test/java/org/apache/shiro/lang/util/ClassUtilsTest.java b/lang/src/test/java/org/apache/shiro/lang/util/ClassUtilsTest.java new file mode 100644 index 0000000000..497e58eb08 --- /dev/null +++ b/lang/src/test/java/org/apache/shiro/lang/util/ClassUtilsTest.java @@ -0,0 +1,88 @@ +/* + * 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.shiro.lang.util; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + + +class ClassUtilsTest { + + @Test + void testGetPrimitiveClasses() throws UnknownClassException { + + assertEquals(ClassUtils.forName("boolean"), boolean.class); + assertEquals(ClassUtils.forName("byte"), byte.class); + assertEquals(ClassUtils.forName("char"), char.class); + assertEquals(ClassUtils.forName("short"), short.class); + assertEquals(ClassUtils.forName("int"), int.class); + assertEquals(ClassUtils.forName("long"), long.class); + assertEquals(ClassUtils.forName("float"), float.class); + assertEquals(ClassUtils.forName("double"), double.class); + assertEquals(ClassUtils.forName("void"), void.class); + + assertEquals(ClassUtils.forName(boolean.class.getName()), boolean.class); + assertEquals(ClassUtils.forName(byte.class.getName()), byte.class); + assertEquals(ClassUtils.forName(char.class.getName()), char.class); + assertEquals(ClassUtils.forName(short.class.getName()), short.class); + assertEquals(ClassUtils.forName(int.class.getName()), int.class); + assertEquals(ClassUtils.forName(long.class.getName()), long.class); + assertEquals(ClassUtils.forName(float.class.getName()), float.class); + assertEquals(ClassUtils.forName(double.class.getName()), double.class); + assertEquals(ClassUtils.forName(void.class.getName()), void.class); + + } + + @Test + void testGetPrimitiveArrays() throws UnknownClassException { + + assertEquals(ClassUtils.forName("[Z"), boolean[].class); + assertEquals(ClassUtils.forName("[B"), byte[].class); + assertEquals(ClassUtils.forName("[C"), char[].class); + assertEquals(ClassUtils.forName("[S"), short[].class); + assertEquals(ClassUtils.forName("[I"), int[].class); + assertEquals(ClassUtils.forName("[J"), long[].class); + assertEquals(ClassUtils.forName("[F"), float[].class); + assertEquals(ClassUtils.forName("[D"), double[].class); + + + assertEquals(ClassUtils.forName(boolean[].class.getName()), boolean[].class); + assertEquals(ClassUtils.forName(byte[].class.getName()), byte[].class); + assertEquals(ClassUtils.forName(char[].class.getName()), char[].class); + assertEquals(ClassUtils.forName(short[].class.getName()), short[].class); + assertEquals(ClassUtils.forName(int[].class.getName()), int[].class); + assertEquals(ClassUtils.forName(long[].class.getName()), long[].class); + assertEquals(ClassUtils.forName(float[].class.getName()), float[].class); + assertEquals(ClassUtils.forName(double[].class.getName()), double[].class); + } + + @Test + void testGetClass() { + assertEquals(ClassUtils.forName("java.lang.String"), String.class); + assertEquals(ClassUtils.forName("[Ljava.lang.String;"), String[].class); + assertEquals(ClassUtils.forName(String.class.getName()), String.class); + assertEquals(ClassUtils.forName(String[].class.getName()), String[].class); + + assertEquals(ClassUtils.forName("org.apache.shiro.lang.util.ClassUtilsTest"), ClassUtilsTest.class); + assertEquals(ClassUtils.forName("[Lorg.apache.shiro.lang.util.ClassUtilsTest;"), ClassUtilsTest[].class); + assertEquals(ClassUtils.forName(ClassUtilsTest.class.getName()), ClassUtilsTest.class); + assertEquals(ClassUtils.forName(ClassUtilsTest[].class.getName()), ClassUtilsTest[].class); + } +}