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;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
29 import com.google.common.base.Preconditions;
31 public final class JavassistUtils {
32 private static final Logger LOG = LoggerFactory.getLogger(JavassistUtils.class);
34 private static final Map<ClassPool, JavassistUtils> INSTANCES = new WeakHashMap<>();
35 private final Map<ClassLoader, ClassPath> loaderClassPaths = new WeakHashMap<>();
36 private final Lock lock = new ReentrantLock();
37 private final ClassPool classPool;
40 * @deprecated Use {@link #forClassPool(ClassPool)} instead.
42 * This class provides auto-loading into the classpool. Unfortunately reusing
43 * the same class pool with multiple instances can lead the same classpath
44 * being added multiple times, which lowers performance and leaks memory.
47 public JavassistUtils(final ClassPool pool) {
51 private JavassistUtils(final ClassPool pool, final Object dummy) {
52 // FIXME: Remove 'dummy' once deprecated constructor is removed
53 classPool = Preconditions.checkNotNull(pool);
57 * Get a utility instance for a particular class pool. A new instance is
58 * created if this is a new pool. If an instance already exists, is is
61 * @param pool Backing class pool
62 * @return shared utility instance for specified pool
64 public static synchronized JavassistUtils forClassPool(final ClassPool pool) {
65 JavassistUtils ret = INSTANCES.get(Preconditions.checkNotNull(pool));
67 ret = new JavassistUtils(pool, null);
68 INSTANCES.put(pool, ret);
73 public Lock getLock() {
77 public void method(final CtClass it, final Class<? extends Object> returnType, final String name,
78 final Class<? extends Object> parameter, final MethodGenerator function1) throws CannotCompileException {
79 final CtClass[] pa = new CtClass[] { asCtClass(parameter) };
80 final CtMethod _ctMethod = new CtMethod(asCtClass(returnType), name, pa, it);
82 final CtMethod method = _ctMethod;
83 function1.process(method);
87 public void method(final CtClass it, final Class<? extends Object> returnType, final String name,
88 final Collection<? extends Class<?>> parameters, final MethodGenerator function1) throws CannotCompileException {
89 final CtClass[] pa = new CtClass[parameters.size()];
92 for (Class<? extends Object> parameter : parameters) {
93 pa[i] = asCtClass(parameter);
97 final CtMethod method = new CtMethod(asCtClass(returnType), name, pa, it);
98 function1.process(method);
102 public void staticMethod(final CtClass it, final Class<? extends Object> returnType, final String name,
103 final Class<? extends Object> parameter, final MethodGenerator function1) throws CannotCompileException {
104 final CtClass[] pa = new CtClass[] { asCtClass(parameter) };
105 final CtMethod _ctMethod = new CtMethod(asCtClass(returnType), name, pa, it);
106 final CtMethod method = _ctMethod;
107 function1.process(method);
108 it.addMethod(method);
111 public void implementMethodsFrom(final CtClass target, final CtClass source, final MethodGenerator function1) throws CannotCompileException {
112 for (CtMethod method : source.getMethods()) {
113 if (method.getDeclaringClass() == source) {
114 CtMethod redeclaredMethod = new CtMethod(method, target, null);
115 function1.process(redeclaredMethod);
116 target.addMethod(redeclaredMethod);
121 public CtClass createClass(final String fqn, final ClassGenerator cls) {
122 CtClass target = classPool.makeClass(fqn);
127 public CtClass createClass(final String fqn, final CtClass superInterface, final ClassGenerator cls) {
128 CtClass target = classPool.makeClass(fqn);
129 implementsType(target, superInterface);
134 public void implementsType(final CtClass it, final CtClass supertype) {
135 Preconditions.checkArgument(supertype.isInterface(), "Supertype must be interface");
136 it.addInterface(supertype);
139 public CtClass asCtClass(final Class<? extends Object> class1) {
140 return get(this.classPool, class1);
143 public CtField field(final CtClass it, final String name, final Class<? extends Object> returnValue) throws CannotCompileException {
144 final CtField field = new CtField(asCtClass(returnValue), name, it);
145 field.setModifiers(Modifier.PUBLIC);
150 public CtField staticField(final CtClass it, final String name, final Class<? extends Object> returnValue) throws CannotCompileException {
151 return staticField(it, name, returnValue, null);
154 public CtField staticField(final CtClass it, final String name,
155 final Class<? extends Object> returnValue,
156 SourceCodeGenerator sourceGenerator) throws CannotCompileException {
157 final CtField field = new CtField(asCtClass(returnValue), name, it);
158 field.setModifiers(Modifier.PUBLIC + Modifier.STATIC);
161 if (sourceGenerator != null) {
162 sourceGenerator.appendField(field, null);
168 public CtClass get(final ClassPool pool, final Class<? extends Object> cls) {
170 return pool.get(cls.getName());
171 } catch (NotFoundException nfe1) {
172 appendClassLoaderIfMissing(cls.getClassLoader());
174 return pool.get(cls.getName());
175 } catch (final NotFoundException nfe2) {
176 LOG.warn("Appending ClassClassPath for {}", cls, nfe2);
177 pool.appendClassPath(new ClassClassPath(cls));
179 return pool.get(cls.getName());
180 } catch (NotFoundException e) {
181 LOG.warn("Failed to load class {} from pool {}", cls, pool, e);
182 throw new IllegalStateException("Failed to load class", e);
188 public synchronized void appendClassLoaderIfMissing(final ClassLoader loader) {
189 if (!loaderClassPaths.containsKey(loader)) {
190 final ClassPath ctLoader = new LoaderClassPath(loader);
191 classPool.appendClassPath(ctLoader);
192 loaderClassPaths.put(loader, ctLoader);
196 public void ensureClassLoader(final Class<?> child) {
197 appendClassLoaderIfMissing(child.getClassLoader());