All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.inject.rebind.GinBridgeClassLoader Maven / Gradle / Ivy

/*
 * Copyright 2011 Google Inc.
 *
 * Licensed 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 com.google.gwt.inject.rebind;

import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.dev.javac.CompilationState;
import com.google.gwt.dev.javac.CompiledClass;
import com.google.gwt.dev.javac.StandardGeneratorContext;

import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

/**
 * Gin-internal class loader that allows us to load classes generated by other generators and
 * super-source.
 *
 * 

In most cases, Gin needs access to the GWT version of a class (whether it is unmodified, * created by a generator or a super-source version) so this is the default version provided by this * class loader. The exception are JRE classes (which cannot be loaded by a custom class loader), * classes that are also used in the Gin Generator "rebind" code (otherwise class literal * comparisons yield strange results) and classes that are defined as super-source by Gin but must * be their "normal" self during the generator run. These exceptions are loaded with the system * class loader. * *

If the class is not available to GWT, we attempt to load it through the system class loader. * *

Unfortunately, GWT does not like to expose internal details like the compilation state and its * bytes. For now, we use reflection to access this internal state but in the long term we should * switch to other strategies such as running javac on source (which we'd need to reverse-engineer * from parsing the GWT AST). */ class GinBridgeClassLoader extends ClassLoader { private final TreeLogger logger; private final GeneratorContext context; /** * Packages that should not be loaded from GWT. */ private final Collection exceptedPackages; // Lazily load class files from compilation state. private boolean loadedClassFiles = false; private Map classFileMap; GinBridgeClassLoader(GeneratorContext context, TreeLogger logger, Collection exceptedPackages) { super(GinBridgeClassLoader.class.getClassLoader()); // Use own class loader. this.context = context; this.logger = logger; this.exceptedPackages = getExceptedPackages(exceptedPackages); } private static Collection getExceptedPackages(Collection superSourceExceptions) { Set names = new LinkedHashSet(); for (String name : superSourceExceptions) { if (name.endsWith(".")) { names.add(name); } else { names.add(name + "."); } } // Make sure we're not loading JRE classes through a non-system class loader (which is not // allowed). names.add("java."); // Annotation loading will require sun.reflect APIs, even when they're referenced from // and present in client code. names.add("sun.reflect."); return names; } /** * @inheritDoc * * Gin class loading implementation, making sure that classes are loaded consistently and can be * GWT generated or super-source classes. See description {@link GinBridgeClassLoader above}. */ @Override protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { Class clazz = findLoadedClass(name); if (clazz == null) { if (inExceptedPackage(name)) { clazz = super.loadClass(name, false); } else { try { clazz = findClass(name); } catch (ClassNotFoundException e) { clazz = super.loadClass(name, false); if (!clazz.isAnnotation()) { // Annotations are always safe to load logger.log(Type.WARN, String.format( "Class %s is used in Gin, but not available in GWT client code.", name)); } } } } if (resolve) { resolveClass(clazz); } return clazz; } private boolean inExceptedPackage(String name) { for (String pkg : exceptedPackages) { if (name.startsWith(pkg)) { return true; } } return false; } /** * Looks up classes in GWT's compilation state. */ @Override protected Class findClass(String name) throws ClassNotFoundException { if (!loadedClassFiles) { classFileMap = extractClassFileMap(); loadedClassFiles = true; } if (classFileMap == null) { throw new ClassNotFoundException(name); } String internalName = name.replace('.', '/'); CompiledClass compiledClass = classFileMap.get(internalName); if (compiledClass == null) { throw new ClassNotFoundException(name); } // Make sure the class's package is present. String pkg = compiledClass.getPackageName(); if (getPackage(pkg) == null) { definePackage(pkg, null, null, null, null, null, null, null); } byte[] bytes = compiledClass.getBytes(); return defineClass(name, bytes, 0, bytes.length); } /** * Retrieves class definitions from a {@link GeneratorContext} by downcasting. */ private Map extractClassFileMap() { if (context instanceof StandardGeneratorContext) { StandardGeneratorContext standardContext = (StandardGeneratorContext) context; return standardContext.getCompilationState().getClassFileMap(); } else { logger.log(TreeLogger.Type.WARN, String.format("Could not load generated classes from GWT context, " + "encountered unexpected generator type %s.", context.getClass())); return null; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy