2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.sal.binding.generator.util;
10 import java.util.Collection;
12 import java.util.WeakHashMap;
13 import java.util.concurrent.locks.Lock;
14 import java.util.concurrent.locks.ReentrantLock;
16 import javassist.CannotCompileException;
17 import javassist.ClassClassPath;
18 import javassist.ClassPath;
19 import javassist.ClassPool;
20 import javassist.CtClass;
21 import javassist.CtField;
22 import javassist.CtMethod;
23 import javassist.LoaderClassPath;
24 import javassist.Modifier;
25 import javassist.NotFoundException;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
30 import com.google.common.base.Preconditions;
32 public final class JavassistUtils {
33 private static final Logger LOG = LoggerFactory.getLogger(JavassistUtils.class);
35 private static final Map<ClassPool, JavassistUtils> INSTANCES = new WeakHashMap<>();
36 private final Map<ClassLoader, ClassPath> loaderClassPaths = new WeakHashMap<>();
37 private final Lock lock = new ReentrantLock();
38 private final ClassPool classPool;
41 * @deprecated Use {@link #forClassPool(ClassPool)} instead.
43 * This class provides auto-loading into the classpool. Unfortunately reusing
44 * the same class pool with multiple instances can lead the same classpath
45 * being added multiple times, which lowers performance and leaks memory.
48 public JavassistUtils(final ClassPool pool) {
52 private JavassistUtils(final ClassPool pool, final Object dummy) {
53 // FIXME: Remove 'dummy' once deprecated constructor is removed
54 classPool = Preconditions.checkNotNull(pool);
58 * Get a utility instance for a particular class pool. A new instance is
59 * created if this is a new pool. If an instance already exists, is is
62 * @param pool Backing class pool
63 * @return shared utility instance for specified pool
65 public static synchronized JavassistUtils forClassPool(final ClassPool pool) {
66 JavassistUtils ret = INSTANCES.get(Preconditions.checkNotNull(pool));
68 ret = new JavassistUtils(pool, null);
69 INSTANCES.put(pool, ret);
74 public Lock getLock() {
78 public void method(final CtClass it, final Class<? extends Object> returnType, final String name,
79 final Class<? extends Object> parameter, final MethodGenerator function1) throws CannotCompileException {
80 final CtClass[] pa = new CtClass[] { asCtClass(parameter) };
81 final CtMethod _ctMethod = new CtMethod(asCtClass(returnType), name, pa, it);
83 final CtMethod method = _ctMethod;
84 function1.process(method);
88 public void method(final CtClass it, final Class<? extends Object> returnType, final String name,
89 final Collection<? extends Class<?>> parameters, final MethodGenerator function1) throws CannotCompileException {
90 final CtClass[] pa = new CtClass[parameters.size()];
93 for (Class<? extends Object> parameter : parameters) {
94 pa[i] = asCtClass(parameter);
98 final CtMethod method = new CtMethod(asCtClass(returnType), name, pa, it);
99 function1.process(method);
100 it.addMethod(method);
103 public void staticMethod(final CtClass it, final Class<? extends Object> returnType, final String name,
104 final Class<? extends Object> parameter, final MethodGenerator function1) throws CannotCompileException {
105 final CtClass[] pa = new CtClass[] { asCtClass(parameter) };
106 final CtMethod _ctMethod = new CtMethod(asCtClass(returnType), name, pa, it);
107 final CtMethod method = _ctMethod;
108 function1.process(method);
109 it.addMethod(method);
112 public void implementMethodsFrom(final CtClass target, final CtClass source, final MethodGenerator function1) throws CannotCompileException {
113 for (CtMethod method : source.getMethods()) {
114 if (method.getDeclaringClass() == source) {
115 CtMethod redeclaredMethod = new CtMethod(method, target, null);
116 function1.process(redeclaredMethod);
117 target.addMethod(redeclaredMethod);
122 public CtClass createClass(final String fqn, final ClassGenerator cls) {
123 CtClass target = classPool.makeClass(fqn);
128 public CtClass createClass(final String fqn, final CtClass superInterface, final ClassGenerator cls) {
129 CtClass target = classPool.makeClass(fqn);
130 implementsType(target, superInterface);
135 public void implementsType(final CtClass it, final CtClass supertype) {
136 Preconditions.checkArgument(supertype.isInterface(), "Supertype must be interface");
137 it.addInterface(supertype);
140 public CtClass asCtClass(final Class<? extends Object> class1) {
141 return get(this.classPool, class1);
144 public CtField field(final CtClass it, final String name, final Class<? extends Object> returnValue) throws CannotCompileException {
145 final CtField field = new CtField(asCtClass(returnValue), name, it);
146 field.setModifiers(Modifier.PUBLIC);
151 public CtField staticField(final CtClass it, final String name, final Class<? extends Object> returnValue) throws CannotCompileException {
152 final CtField field = new CtField(asCtClass(returnValue), name, it);
153 field.setModifiers(Modifier.PUBLIC + Modifier.STATIC);
158 public CtClass get(final ClassPool pool, final Class<? extends Object> cls) {
160 return pool.get(cls.getName());
161 } catch (NotFoundException nfe1) {
162 appendClassLoaderIfMissing(cls.getClassLoader());
164 return pool.get(cls.getName());
165 } catch (final NotFoundException nfe2) {
166 LOG.warn("Appending ClassClassPath for {}", cls, nfe2);
167 pool.appendClassPath(new ClassClassPath(cls));
169 return pool.get(cls.getName());
170 } catch (NotFoundException e) {
171 LOG.warn("Failed to load class {} from pool {}", cls, pool, e);
172 throw new IllegalStateException("Failed to load class", e);
178 public synchronized void appendClassLoaderIfMissing(final ClassLoader loader) {
179 if (!loaderClassPaths.containsKey(loader)) {
180 final ClassPath ctLoader = new LoaderClassPath(loader);
181 classPool.appendClassPath(ctLoader);
182 loaderClassPaths.put(loader, ctLoader);
186 public void ensureClassLoader(final Class<?> child) {
187 appendClassLoaderIfMissing(child.getClassLoader());