View Javadoc
1   /*
2    * JavaBean Tester (https://github.com/hazendaz/javabean-tester)
3    *
4    * Copyright 2012-2021 Hazendaz.
5    *
6    * All rights reserved. This program and the accompanying materials
7    * are made available under the terms of The Apache Software License,
8    * Version 2.0 which accompanies this distribution, and is available at
9    * http://www.apache.org/licenses/LICENSE-2.0.txt
10   *
11   * Contributors:
12   *     CodeBox (Rob Dawson).
13   *     Hazendaz (Jeremy Landis).
14   */
15  package com.codebox.builders;
16  
17  import java.util.HashMap;
18  import java.util.Map;
19  import java.util.Map.Entry;
20  import javassist.CannotCompileException;
21  import javassist.ClassPool;
22  import javassist.CtClass;
23  import javassist.CtField;
24  import javassist.CtMethod;
25  import javassist.NotFoundException;
26  
27  import org.slf4j.Logger;
28  import org.slf4j.LoggerFactory;
29  
30  /**
31   * The Class ExtensionBuilder.
32   *
33   * @param <T>
34   *            the generic type
35   */
36  public class ExtensionBuilder<T> {
37  
38      /** The Constant LOGGER. */
39      private static final Logger LOGGER = LoggerFactory.getLogger(ExtensionBuilder.class);
40  
41      /**
42       * Generate.
43       *
44       * @param clazz
45       *            the clazz
46       *
47       * @return the class
48       *
49       * @throws NotFoundException
50       *             the not found exception
51       * @throws CannotCompileException
52       *             the cannot compile exception
53       */
54      public Class<?> generate(final Class<T> clazz) throws NotFoundException, CannotCompileException {
55          try {
56              // If extension already recreated, return it
57              return Class.forName(clazz.getName() + "Extension");
58          } catch (final ClassNotFoundException e) {
59              // No extension exists, so create it
60              ExtensionBuilder.LOGGER.trace("No extension exists, so create it", e);
61          }
62  
63          final ClassPool pool = ClassPool.getDefault();
64          final CtClass cc = pool.makeClass(clazz.getName() + "Extension");
65  
66          // add super class
67          cc.setSuperclass(ExtensionBuilder.resolveCtClass(clazz));
68  
69          final Map<String, Class<?>> properties = new HashMap<>();
70          properties.put("jbExtension1", String.class);
71          properties.put("jbExtension2", String.class);
72          properties.put("jbExtension3", String.class);
73          properties.put("jbExtension4", String.class);
74  
75          for (final Entry<String, Class<?>> entry : properties.entrySet()) {
76  
77              // Add field
78              cc.addField(new CtField(ExtensionBuilder.resolveCtClass(entry.getValue()), entry.getKey(), cc));
79  
80              // Add getter
81              cc.addMethod(ExtensionBuilder.generateGetter(cc, entry.getKey(), entry.getValue()));
82  
83              // Add setter
84              cc.addMethod(ExtensionBuilder.generateSetter(cc, entry.getKey(), entry.getValue()));
85          }
86  
87          return cc.toClass();
88      }
89  
90      /**
91       * Generate getter.
92       *
93       * @param declaringClass
94       *            the declaring class
95       * @param fieldName
96       *            the field name
97       * @param fieldClass
98       *            the field class
99       *
100      * @return the ct method
101      *
102      * @throws CannotCompileException
103      *             the cannot compile exception
104      */
105     private static CtMethod generateGetter(final CtClass declaringClass, final String fieldName,
106             final Class<?> fieldClass) throws CannotCompileException {
107         final StringBuilder sb = new StringBuilder();
108         sb.append("public ");
109         sb.append(fieldClass.getName());
110         sb.append(" get");
111         sb.append(fieldName.substring(0, 1).toUpperCase());
112         sb.append(fieldName.substring(1));
113         sb.append("(){");
114         sb.append("return this.");
115         sb.append(fieldName);
116         sb.append(";");
117         sb.append("}");
118         return CtMethod.make(sb.toString(), declaringClass);
119     }
120 
121     /**
122      * Generate setter.
123      *
124      * @param declaringClass
125      *            the declaring class
126      * @param fieldName
127      *            the field name
128      * @param fieldClass
129      *            the field class
130      *
131      * @return the ct method
132      *
133      * @throws CannotCompileException
134      *             the cannot compile exception
135      */
136     private static CtMethod generateSetter(final CtClass declaringClass, final String fieldName,
137             final Class<?> fieldClass) throws CannotCompileException {
138         final StringBuilder sb = new StringBuilder();
139         sb.append("public void set");
140         sb.append(fieldName.substring(0, 1).toUpperCase());
141         sb.append(fieldName.substring(1));
142         sb.append("(");
143         sb.append(fieldClass.getName());
144         sb.append(" ");
145         sb.append(fieldName);
146         sb.append(")");
147         sb.append("{");
148         sb.append("this.");
149         sb.append(fieldName);
150         sb.append("=");
151         sb.append(fieldName);
152         sb.append(";");
153         sb.append("}");
154         return CtMethod.make(sb.toString(), declaringClass);
155     }
156 
157     /**
158      * Resolve ct class.
159      *
160      * @param clazz
161      *            the clazz
162      *
163      * @return the ct class
164      *
165      * @throws NotFoundException
166      *             the not found exception
167      */
168     private static CtClass resolveCtClass(final Class<?> clazz) throws NotFoundException {
169         return ClassPool.getDefault().get(clazz.getName());
170     }
171 
172 }