| /* |
| * Copyright (c) 2006, 2021 Oracle and/or its affiliates. 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, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Oracle - initial API and implementation |
| // |
| package org.eclipse.persistence.jpa.tests.jpql.tools.spi.java; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| import org.eclipse.persistence.jpa.jpql.tools.TypeHelper; |
| import org.eclipse.persistence.jpa.jpql.tools.spi.IType; |
| import org.eclipse.persistence.jpa.jpql.tools.spi.ITypeRepository; |
| |
| /** |
| * The concrete implementation of {@link ITypeRepository} that is wrapping the Java class loader. |
| * |
| * @version 2.4 |
| * @since 2.3 |
| * @author Pascal Filion |
| */ |
| @SuppressWarnings("nls") |
| public class JavaTypeRepository implements ITypeRepository { |
| |
| /** |
| * The repository used to access the application's classes. |
| */ |
| private final ClassLoader classLoader; |
| |
| /** |
| * The helper that gives access to the most common {@link IType types}. |
| */ |
| private TypeHelper typeHelper; |
| |
| /** |
| * The types that have been cached for faster access. |
| */ |
| private final Map<String, JavaType> types; |
| |
| /** |
| * The {@link IType} that represents a unresolvable or simply an unknown type, which is created |
| * when {@link #getType(String)} is invoked with {@link IType#UNRESOLVABLE_TYPE}. |
| */ |
| private JavaType unresolvableType; |
| |
| /** |
| * Creates a new <code>JavaTypeRepository</code>. |
| * |
| * @param classLoader The repository used to access the application's classes |
| */ |
| public JavaTypeRepository(ClassLoader classLoader) { |
| super(); |
| this.classLoader = classLoader; |
| this.types = new HashMap<String, JavaType>(); |
| } |
| |
| /** |
| * Retrieves the Java type for the given type name, which has to be the fully qualified type name. |
| * |
| * @param typeName The fully qualified type name |
| * @return The Java type if it could be retrieved; <code>null</code> otherwise |
| */ |
| protected Class<?> attemptLoadType(String typeName) { |
| |
| if (typeName.equals("boolean")) return Boolean .TYPE; |
| if (typeName.equals("byte")) return Byte .TYPE; |
| if (typeName.equals("char")) return Character.TYPE; |
| if (typeName.equals("double")) return Double .TYPE; |
| if (typeName.equals("float")) return Float .TYPE; |
| if (typeName.equals("int")) return Integer .TYPE; |
| if (typeName.equals("long")) return Long .TYPE; |
| if (typeName.equals("short")) return Short .TYPE; |
| |
| try { |
| return classLoader.loadClass(typeName); |
| } |
| catch (ClassNotFoundException e) { |
| return null; |
| } |
| } |
| |
| protected JavaType buildType(Class<?> javaType) { |
| JavaType type = new JavaType(this, javaType); |
| types.put(javaType.getName(), type); |
| return type; |
| } |
| |
| protected JavaType buildType(String typeName) { |
| return new JavaType(this, typeName); |
| } |
| |
| /** |
| * Returns the {@link ClassLoader} that is used to load Java classes. |
| * |
| * @return The {@link ClassLoader} that is used to load Java classes |
| */ |
| public ClassLoader getClassLoader() { |
| return classLoader; |
| } |
| |
| @Override |
| public IType getEnumType(String enumTypeName) { |
| |
| // Get the position of the last dot so we can remove the constant |
| int lastDotIndex = enumTypeName.lastIndexOf("."); |
| |
| if (lastDotIndex == -1) { |
| return null; |
| } |
| |
| // Retrieve the fully qualified enum type name |
| String typeName = enumTypeName.substring(0, lastDotIndex); |
| |
| // Attempt to load the enum type |
| IType type = loadTypeImp(typeName); |
| return type.isEnum() ? type : null; |
| } |
| |
| @Override |
| public JavaType getType(Class<?> javaClass) { |
| return getType(javaClass.getName()); |
| } |
| |
| @Override |
| public JavaType getType(String typeName) { |
| |
| if (typeName == IType.UNRESOLVABLE_TYPE) { |
| return unresolvableType(); |
| } |
| |
| if (typeName.charAt(0) == '[') { |
| return loadArrayType(typeName); |
| } |
| |
| return loadTypeImp(typeName); |
| } |
| |
| @Override |
| public TypeHelper getTypeHelper() { |
| if (typeHelper == null) { |
| typeHelper = new TypeHelper(this); |
| } |
| return typeHelper; |
| } |
| |
| protected JavaType loadArrayType(String typeName) { |
| |
| JavaType type = types.get(typeName); |
| |
| if (type == null) { |
| try { |
| type = new JavaType(this, Class.forName(typeName)); |
| } |
| catch (ClassNotFoundException f) { |
| type = new JavaType(this, typeName); |
| } |
| types.put(typeName, type); |
| } |
| |
| return type; |
| } |
| |
| protected JavaType loadInnerType(String typeName) { |
| |
| int index = typeName.lastIndexOf("."); |
| |
| if (index == -1) { |
| return null; |
| } |
| |
| StringBuilder sb = new StringBuilder(); |
| sb.append(typeName.substring(0, index)); |
| sb.append("$"); |
| sb.append(typeName.substring(index + 1, typeName.length())); |
| typeName = sb.toString(); |
| |
| return loadTypeImp(typeName); |
| } |
| |
| protected JavaType loadTypeImp(String typeName) { |
| |
| JavaType type = types.get(typeName); |
| |
| // The type was already cached, simply return it |
| if (type != null) { |
| return type; |
| } |
| |
| // Attempt to load the Java type |
| Class<?> javaType = attemptLoadType(typeName); |
| |
| // A Java type exists, return it |
| if (javaType != null) { |
| return buildType(javaType); |
| } |
| |
| // Now try with a possible inner type |
| type = loadInnerType(typeName); |
| |
| if (type == null) { |
| type = buildType(typeName); |
| } |
| |
| return type; |
| } |
| |
| protected JavaType unresolvableType() { |
| if (unresolvableType == null) { |
| unresolvableType = new JavaType(this, IType.UNRESOLVABLE_TYPE); |
| } |
| return unresolvableType; |
| } |
| } |