jakarta.el.ImportHandler Maven / Gradle / Ivy
/*
* Copyright (c) 2012, 2019 Oracle and/or its affiliates and others.
* All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package jakarta.el;
import static java.lang.reflect.Modifier.isAbstract;
import static java.lang.reflect.Modifier.isInterface;
import static java.lang.reflect.Modifier.isPublic;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
/**
* Handles imports of class names and package names. An imported package name implicitly imports all the classes in the
* package. A class that has been imported can be used without its package name. The name is resolved to its full
* (package and class) name at evaluation time.
*/
public class ImportHandler {
private Map classNameMap = new HashMap<>();
private Map> classMap = new HashMap<>();
private Map staticNameMap = new HashMap<>();
private HashSet notAClass = new HashSet<>();
private List packages = new ArrayList<>();
{
importPackage("java.lang");
}
/**
* Import a static field or method.
*
* @param name The static member name, including the full class name, to be imported
* @throws ELException if the name does not include a ".".
*/
public void importStatic(String name) throws ELException {
int i = name.lastIndexOf('.');
if (i <= 0) {
throw new ELException("The name " + name + " is not a full static member name");
}
String memberName = name.substring(i + 1);
String className = name.substring(0, i);
staticNameMap.put(memberName, className);
}
/**
* Import a class.
*
* @param name The full class name of the class to be imported
* @throws ELException if the name does not include a ".".
*/
public void importClass(String name) throws ELException {
int i = name.lastIndexOf('.');
if (i <= 0) {
throw new ELException("The name " + name + " is not a full class name");
}
String className = name.substring(i + 1);
classNameMap.put(className, name);
}
/**
* Import all the classes in a package.
*
* @param packageName The package name to be imported
*/
public void importPackage(String packageName) {
packages.add(packageName);
}
/**
* Resolve a class name.
*
* @param name The name of the class (without package name) to be resolved.
* @return If the class has been imported previously, with {@link #importClass} or {@link #importPackage}, then its
* Class instance. Otherwise null
.
* @throws ELException if the class is abstract or is an interface, or not public.
*/
public Class> resolveClass(String name) {
String className = classNameMap.get(name);
if (className != null) {
return resolveClassFor(className);
}
for (String packageName : packages) {
String fullClassName = packageName + "." + name;
Class> c = resolveClassFor(fullClassName);
if (c != null) {
classNameMap.put(name, fullClassName);
return c;
}
}
return null;
}
/**
* Resolve a static field or method name.
*
* @param name The name of the member(without package and class name) to be resolved.
* @return If the field or method has been imported previously, with {@link #importStatic}, then the class object
* representing the class that declares the static field or method. Otherwise null
.
* @throws ELException if the class is not public, or is abstract or is an interface.
*/
public Class> resolveStatic(String name) {
String className = staticNameMap.get(name);
if (className != null) {
Class> c = resolveClassFor(className);
if (c != null) {
return c;
}
}
return null;
}
private Class> resolveClassFor(String className) {
Class> c = classMap.get(className);
if (c != null) {
return c;
}
c = getClassFor(className);
if (c != null) {
checkModifiers(c.getModifiers());
classMap.put(className, c);
}
return c;
}
private Class> getClassFor(String className) {
if (!notAClass.contains(className)) {
try {
return Class.forName(className, false, Thread.currentThread().getContextClassLoader());
// Some operating systems have case-insensitive path names. An example is Windows if className is
// attempting to be resolved from a wildcard import a java.lang.NoClassDefFoundError may be thrown as
// the expected case for the type likely doesn't match. See
// https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8024775 and
// https://bugs.openjdk.java.net/browse/JDK-8133522.
} catch (ClassNotFoundException | NoClassDefFoundError ex) {
notAClass.add(className);
}
}
return null;
}
private void checkModifiers(int modifiers) {
if (isAbstract(modifiers) || isInterface(modifiers) || !isPublic((modifiers))) {
throw new ELException("Imported class must be public, and cannot be abstract or an interface");
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy