├── .gitignore
├── .travis.yml
├── README.md
├── pom.xml
└── src
├── main
└── java
│ └── com
│ └── itranswarp
│ └── compiler
│ ├── JavaStringCompiler.java
│ ├── MemoryClassLoader.java
│ └── MemoryJavaFileManager.java
└── test
└── java
└── com
└── itranswarp
├── compiler
└── JavaStringCompilerTest.java
└── on
└── the
└── fly
├── BeanProxy.java
└── User.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # Java.gitignore ##############################################################
2 |
3 | *.class
4 |
5 | # Mobile Tools for Java (J2ME)
6 | .mtj.tmp/
7 |
8 | # Package Files #
9 | *.jar
10 | *.war
11 | *.ear
12 |
13 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
14 | hs_err_pid*
15 |
16 | # Maven.gitignore #############################################################
17 |
18 | target/
19 | pom.xml.tag
20 | pom.xml.releaseBackup
21 | pom.xml.versionsBackup
22 | pom.xml.next
23 | release.properties
24 | dependency-reduced-pom.xml
25 | buildNumber.properties
26 | .mvn/timing.properties
27 |
28 | # Eclipse.gitignore ###########################################################
29 |
30 | *.pydevproject
31 | .metadata
32 | .gradle
33 | bin/
34 | tmp/
35 | *.tmp
36 | *.bak
37 | *.swp
38 | *~.nib
39 | local.properties
40 | .settings/
41 | .loadpath
42 |
43 | # Eclipse Core
44 | .project
45 |
46 | # External tool builders
47 | .externalToolBuilders/
48 | .recommenders/
49 |
50 | # Locally stored "Eclipse launch configurations"
51 | *.launch
52 |
53 | # CDT-specific
54 | .cproject
55 |
56 | # JDT-specific (Eclipse Java Development Tools)
57 | .classpath
58 |
59 | # Java annotation processor (APT)
60 | .factorypath
61 |
62 | # PDT-specific
63 | .buildpath
64 |
65 | # sbteclipse plugin
66 | .target
67 |
68 | # TeXlipse plugin
69 | .texlipse
70 |
71 | # NetBeans.gitignore ##########################################################
72 |
73 | nbproject/private/
74 | build/
75 | nbbuild/
76 | dist/
77 | nbdist/
78 | nbactions.xml
79 | nb-configuration.xml
80 | .nb-gradle/
81 |
82 | # JetBrains.gitignore #########################################################
83 |
84 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
85 |
86 | *.iml
87 |
88 | ## Directory-based project format:
89 | .idea/
90 | # if you remove the above rule, at least ignore the following:
91 |
92 | # User-specific stuff:
93 | # .idea/workspace.xml
94 | # .idea/tasks.xml
95 | # .idea/dictionaries
96 |
97 | # Sensitive or high-churn files:
98 | # .idea/dataSources.ids
99 | # .idea/dataSources.xml
100 | # .idea/sqlDataSources.xml
101 | # .idea/dynamic.xml
102 | # .idea/uiDesigner.xml
103 |
104 | # Gradle:
105 | # .idea/gradle.xml
106 | # .idea/libraries
107 |
108 | # Mongo Explorer plugin:
109 | # .idea/mongoSettings.xml
110 |
111 | ## File-based project format:
112 | *.ipr
113 | *.iws
114 |
115 | ## Plugin-specific files:
116 |
117 | # IntelliJ
118 | /out/
119 |
120 | # mpeltonen/sbt-idea plugin
121 | .idea_modules/
122 |
123 | # JIRA plugin
124 | atlassian-ide-plugin.xml
125 |
126 | # Crashlytics plugin (for Android Studio and IntelliJ)
127 | com_crashlytics_export_strings.xml
128 | crashlytics.properties
129 | crashlytics-build.properties
130 |
131 | # SublimeText.gitignore #######################################################
132 |
133 | # cache files for sublime text
134 | *.tmlanguage.cache
135 | *.tmPreferences.cache
136 | *.stTheme.cache
137 |
138 | # workspace files are user-specific
139 | *.sublime-workspace
140 |
141 | # project files should be checked into the repository, unless a significant
142 | # proportion of contributors will probably not be using SublimeText
143 | # *.sublime-project
144 |
145 | # sftp configuration file
146 | sftp-config.json
147 |
148 | # Vim.gitignore ###############################################################
149 |
150 | [._]*.s[a-w][a-z]
151 | [._]s[a-w][a-z]
152 | *.un~
153 | Session.vim
154 | .netrwhist
155 | *~
156 |
157 | # Emacs.gitignore #############################################################
158 |
159 | # -*- mode: gitignore; -*-
160 | *~
161 | \#*\#
162 | /.emacs.desktop
163 | /.emacs.desktop.lock
164 | *.elc
165 | auto-save-list
166 | tramp
167 | .\#*
168 |
169 | # Org-mode
170 | .org-id-locations
171 | *_archive
172 |
173 | # flymake-mode
174 | *_flymake.*
175 |
176 | # eshell files
177 | /eshell/history
178 | /eshell/lastdir
179 |
180 | # elpa packages
181 | /elpa/
182 |
183 | # reftex files
184 | *.rel
185 |
186 | # AUCTeX auto folder
187 | /auto/
188 |
189 | # cask packages
190 | .cask/
191 |
192 | # Python ignore ###############################################################
193 |
194 | *.py[cod]
195 |
196 | # C extensions
197 | *.so
198 |
199 | # Packages
200 | *.egg
201 | *.egg-info
202 | dist
203 | build
204 | eggs
205 | parts
206 | bin
207 | var
208 | sdist
209 | develop-eggs
210 | .installed.cfg
211 | lib
212 | lib64
213 | __pycache__
214 |
215 | # Installer logs
216 | pip-log.txt
217 |
218 | # Unit test / coverage reports
219 | .coverage
220 | .tox
221 | nosetests.xml
222 |
223 | # OSX.gitignore ###############################################################
224 |
225 | .DS_Store
226 | .AppleDouble
227 | .LSOverride
228 |
229 | # Icon must end with two \r
230 | Icon
231 |
232 | # Thumbnails
233 | ._*
234 |
235 | # Files that might appear in the root of a volume
236 | .DocumentRevisions-V100
237 | .fseventsd
238 | .Spotlight-V100
239 | .TemporaryItems
240 | .Trashes
241 | .VolumeIcon.icns
242 |
243 | # Directories potentially created on remote AFP share
244 | .AppleDB
245 | .AppleDesktop
246 | Network Trash Folder
247 | Temporary Items
248 | .apdisk
249 |
250 | # Windows.gitignore ###########################################################
251 |
252 | # Windows image file caches
253 | Thumbs.db
254 | ehthumbs.db
255 |
256 | # Folder config file
257 | Desktop.ini
258 |
259 | # Recycle Bin used on file shares
260 | $RECYCLE.BIN/
261 |
262 | # Windows Installer files
263 | *.cab
264 | *.msi
265 | *.msm
266 | *.msp
267 |
268 | # Windows shortcuts
269 | *.lnk
270 |
271 | # Linux.gitignore #############################################################
272 |
273 | *~
274 |
275 | # KDE directory preferences
276 | .directory
277 |
278 | # Linux trash folder which might appear on any partition or disk
279 | .Trash-*
280 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 |
3 | jdk:
4 | - oraclejdk7
5 |
6 | install: mvn install -DskipTests=true -Dgpg.skip=true
7 |
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # compiler
2 |
3 | Compile Java code in memory using Java 6 compiler API.
4 |
5 | [](https://travis-ci.org/michaelliao/compiler)
6 |
7 | ### Why compiler API?
8 |
9 | You can use compiler API to compile generated Java source code and load the compiled classes on-the-fly.
10 |
11 | For example, generate proxy classes using compiler API instead of CGLIB or Javassist.
12 |
13 | ### How to use this compiler?
14 |
15 | Step 1: add maven dependency:
16 |
17 | ```
18 |
19 | com.itranswarp
20 | compiler
21 | 1.0
22 |
23 | ```
24 |
25 | Step 2: compile string and load class:
26 |
27 | ```
28 | public class Main {
29 |
30 | public static void main(String[] args) {
31 | JavaStringCompiler compiler = new JavaStringCompiler();
32 | Map results = compiler.compile("UserProxy.java", JAVA_SOURCE_CODE);
33 | Class> clazz = compiler.loadClass("on.the.fly.UserProxy", results);
34 | // try instance:
35 | User user = (User) clazz.newInstance();
36 | }
37 |
38 | static final String JAVA_SOURCE_CODE = "/* a single java source file */ "
39 | + "package on.the.fly; "
40 | + "public class UserProxy extends test.User { "
41 | + " boolean _dirty = false; "
42 | + " public void setId(String id) { "
43 | + " super.setId(id); "
44 | + " setDirty(true); "
45 | + " } "
46 | + " public void setName(String name) { "
47 | + " super.setName(name); "
48 | + " setDirty(true); "
49 | + " } "
50 | + " public void setCreated(long created) { "
51 | + " super.setCreated(created); "
52 | + " setDirty(true); "
53 | + " } "
54 | + " public void setDirty(boolean dirty) { "
55 | + " this._dirty = dirty; "
56 | + " } "
57 | + " public boolean isDirty() { "
58 | + " return this._dirty; "
59 | + " } "
60 | + "} ";
61 | }
62 | ```
63 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | com.itranswarp
6 | compiler
7 | 1.0
8 | jar
9 |
10 | compiler
11 | Compile Java code in memory using Java 7 compiler API
12 | https://github.com/michaelliao/compiler
13 |
14 |
15 |
16 | The Apache License, Version 2.0
17 | http://www.apache.org/licenses/LICENSE-2.0.txt
18 |
19 |
20 |
21 |
22 |
23 | Michael Liao
24 | askxuefeng@gmail.com
25 | iTranswarp
26 | http://www.liaoxuefeng.com
27 |
28 |
29 |
30 |
31 | https://github.com:michaelliao/compiler.git
32 | scm:git:git@github.com:michaelliao/compiler.git
33 | scm:git:git@github.com:michaelliao/compiler.git
34 |
35 |
36 |
37 |
38 | UTF-8
39 |
40 | 1.0
41 |
42 | yyyyMMdd_HHmmss
43 |
44 | 2.1.1
45 | 4.12
46 |
47 |
48 |
49 |
50 | org.eclipse.persistence
51 | javax.persistence
52 | ${jpa.version}
53 | test
54 |
55 |
56 | junit
57 | junit
58 | ${junit.version}
59 | test
60 |
61 |
62 |
63 |
64 |
65 |
66 | org.apache.maven.plugins
67 | maven-jar-plugin
68 | 2.6
69 |
70 |
71 |
72 | jar
73 |
74 |
75 |
76 |
77 |
78 | org.apache.maven.plugins
79 | maven-compiler-plugin
80 | 3.2
81 |
82 | 1.7
83 | 1.7
84 | -verbose
85 |
86 |
87 |
88 | org.apache.maven.plugins
89 | maven-source-plugin
90 | 2.2.1
91 |
92 |
93 | attach-sources
94 |
95 | jar-no-fork
96 |
97 |
98 |
99 |
100 |
101 | org.apache.maven.plugins
102 | maven-javadoc-plugin
103 | 2.9.1
104 |
105 |
106 | attach-javadocs
107 |
108 | jar
109 |
110 |
111 |
112 |
113 |
114 | org.apache.maven.plugins
115 | maven-gpg-plugin
116 | 1.5
117 |
118 |
119 | sign-artifacts
120 | verify
121 |
122 | sign
123 |
124 |
125 |
126 |
127 |
128 | org.sonatype.plugins
129 | nexus-staging-maven-plugin
130 | 1.6.3
131 | true
132 |
133 | ossrh
134 | https://oss.sonatype.org/
135 | true
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 | ossrh
144 | https://oss.sonatype.org/content/repositories/snapshots
145 |
146 |
147 |
148 | ossrh
149 | Nexus Release Repository
150 | http://oss.sonatype.org/service/local/staging/deploy/maven2/
151 |
152 |
153 |
154 |
--------------------------------------------------------------------------------
/src/main/java/com/itranswarp/compiler/JavaStringCompiler.java:
--------------------------------------------------------------------------------
1 | package com.itranswarp.compiler;
2 |
3 | import java.io.IOException;
4 | import java.util.Arrays;
5 | import java.util.Map;
6 |
7 | import javax.tools.JavaCompiler;
8 | import javax.tools.JavaFileObject;
9 | import javax.tools.StandardJavaFileManager;
10 | import javax.tools.ToolProvider;
11 | import javax.tools.JavaCompiler.CompilationTask;
12 |
13 | /**
14 | * In-memory compile Java source code as String.
15 | *
16 | * @author michael
17 | */
18 | public class JavaStringCompiler {
19 |
20 | JavaCompiler compiler;
21 | StandardJavaFileManager stdManager;
22 |
23 | public JavaStringCompiler() {
24 | this.compiler = ToolProvider.getSystemJavaCompiler();
25 | this.stdManager = compiler.getStandardFileManager(null, null, null);
26 | }
27 |
28 | /**
29 | * Compile a Java source file in memory.
30 | *
31 | * @param fileName
32 | * Java file name, e.g. "Test.java"
33 | * @param source
34 | * The source code as String.
35 | * @return The compiled results as Map that contains class name as key,
36 | * class binary as value.
37 | * @throws IOException
38 | * If compile error.
39 | */
40 | public Map compile(String fileName, String source) throws IOException {
41 | try (MemoryJavaFileManager manager = new MemoryJavaFileManager(stdManager)) {
42 | JavaFileObject javaFileObject = manager.makeStringSource(fileName, source);
43 | CompilationTask task = compiler.getTask(null, manager, null, null, null, Arrays.asList(javaFileObject));
44 | Boolean result = task.call();
45 | if (result == null || !result.booleanValue()) {
46 | throw new RuntimeException("Compilation failed.");
47 | }
48 | return manager.getClassBytes();
49 | }
50 | }
51 |
52 | /**
53 | * Load class from compiled classes.
54 | *
55 | * @param name
56 | * Full class name.
57 | * @param classBytes
58 | * Compiled results as a Map.
59 | * @return The Class instance.
60 | * @throws ClassNotFoundException
61 | * If class not found.
62 | * @throws IOException
63 | * If load error.
64 | */
65 | public Class> loadClass(String name, Map classBytes) throws ClassNotFoundException, IOException {
66 | try (MemoryClassLoader classLoader = new MemoryClassLoader(classBytes)) {
67 | return classLoader.loadClass(name);
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/com/itranswarp/compiler/MemoryClassLoader.java:
--------------------------------------------------------------------------------
1 | package com.itranswarp.compiler;
2 |
3 | import java.net.URL;
4 | import java.net.URLClassLoader;
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | /**
9 | * Load class from byte[] which is compiled in memory.
10 | *
11 | * @author michael
12 | */
13 | class MemoryClassLoader extends URLClassLoader {
14 |
15 | // class name to class bytes:
16 | Map classBytes = new HashMap();
17 |
18 | public MemoryClassLoader(Map classBytes) {
19 | super(new URL[0], MemoryClassLoader.class.getClassLoader());
20 | this.classBytes.putAll(classBytes);
21 | }
22 |
23 | @Override
24 | protected Class> findClass(String name) throws ClassNotFoundException {
25 | byte[] buf = classBytes.get(name);
26 | if (buf == null) {
27 | return super.findClass(name);
28 | }
29 | classBytes.remove(name);
30 | return defineClass(name, buf, 0, buf.length);
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/itranswarp/compiler/MemoryJavaFileManager.java:
--------------------------------------------------------------------------------
1 | package com.itranswarp.compiler;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.FilterOutputStream;
5 | import java.io.IOException;
6 | import java.io.OutputStream;
7 | import java.net.URI;
8 | import java.nio.CharBuffer;
9 | import java.util.HashMap;
10 | import java.util.Map;
11 |
12 | import javax.tools.FileObject;
13 | import javax.tools.ForwardingJavaFileManager;
14 | import javax.tools.JavaFileManager;
15 | import javax.tools.JavaFileObject;
16 | import javax.tools.JavaFileObject.Kind;
17 | import javax.tools.SimpleJavaFileObject;
18 |
19 | /**
20 | * In-memory java file manager.
21 | *
22 | * @author michael
23 | */
24 | class MemoryJavaFileManager extends ForwardingJavaFileManager {
25 |
26 | // compiled classes in bytes:
27 | final Map classBytes = new HashMap();
28 |
29 | MemoryJavaFileManager(JavaFileManager fileManager) {
30 | super(fileManager);
31 | }
32 |
33 | public Map getClassBytes() {
34 | return new HashMap(this.classBytes);
35 | }
36 |
37 | @Override
38 | public void flush() throws IOException {
39 | }
40 |
41 | @Override
42 | public void close() throws IOException {
43 | classBytes.clear();
44 | }
45 |
46 | @Override
47 | public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, Kind kind,
48 | FileObject sibling) throws IOException {
49 | if (kind == Kind.CLASS) {
50 | return new MemoryOutputJavaFileObject(className);
51 | } else {
52 | return super.getJavaFileForOutput(location, className, kind, sibling);
53 | }
54 | }
55 |
56 | JavaFileObject makeStringSource(String name, String code) {
57 | return new MemoryInputJavaFileObject(name, code);
58 | }
59 |
60 | static class MemoryInputJavaFileObject extends SimpleJavaFileObject {
61 |
62 | final String code;
63 |
64 | MemoryInputJavaFileObject(String name, String code) {
65 | super(URI.create("string:///" + name), Kind.SOURCE);
66 | this.code = code;
67 | }
68 |
69 | @Override
70 | public CharBuffer getCharContent(boolean ignoreEncodingErrors) {
71 | return CharBuffer.wrap(code);
72 | }
73 | }
74 |
75 | class MemoryOutputJavaFileObject extends SimpleJavaFileObject {
76 | final String name;
77 |
78 | MemoryOutputJavaFileObject(String name) {
79 | super(URI.create("string:///" + name), Kind.CLASS);
80 | this.name = name;
81 | }
82 |
83 | @Override
84 | public OutputStream openOutputStream() {
85 | return new FilterOutputStream(new ByteArrayOutputStream()) {
86 | @Override
87 | public void close() throws IOException {
88 | out.close();
89 | ByteArrayOutputStream bos = (ByteArrayOutputStream) out;
90 | classBytes.put(name, bos.toByteArray());
91 | }
92 | };
93 | }
94 |
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/test/java/com/itranswarp/compiler/JavaStringCompilerTest.java:
--------------------------------------------------------------------------------
1 | package com.itranswarp.compiler;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import java.lang.reflect.Method;
6 | import java.util.Map;
7 |
8 | import org.junit.Before;
9 | import org.junit.Test;
10 |
11 | import com.itranswarp.on.the.fly.BeanProxy;
12 | import com.itranswarp.on.the.fly.User;
13 |
14 | public class JavaStringCompilerTest {
15 |
16 | JavaStringCompiler compiler;
17 |
18 | @Before
19 | public void setUp() throws Exception {
20 | compiler = new JavaStringCompiler();
21 | }
22 |
23 | static final String SINGLE_JAVA = "/* a single java class to one file */ "
24 | + "package on.the.fly; "
25 | + "import com.itranswarp.on.the.fly.*; "
26 | + "public class UserProxy extends User implements BeanProxy { "
27 | + " boolean _dirty = false; "
28 | + " public void setId(String id) { "
29 | + " super.setId(id); "
30 | + " setDirty(true); "
31 | + " } "
32 | + " public void setName(String name) { "
33 | + " super.setName(name); "
34 | + " setDirty(true); "
35 | + " } "
36 | + " public void setCreated(long created) { "
37 | + " super.setCreated(created); "
38 | + " setDirty(true); "
39 | + " } "
40 | + " public void setDirty(boolean dirty) { "
41 | + " this._dirty = dirty; "
42 | + " } "
43 | + " public boolean isDirty() { "
44 | + " return this._dirty; "
45 | + " } "
46 | + "} ";
47 |
48 | @Test
49 | public void testCompileSingleClass() throws Exception {
50 | Map results = compiler.compile("UserProxy.java", SINGLE_JAVA);
51 | assertEquals(1, results.size());
52 | assertTrue(results.containsKey("on.the.fly.UserProxy"));
53 | Class> clazz = compiler.loadClass("on.the.fly.UserProxy", results);
54 | // get method:
55 | Method setId = clazz.getMethod("setId", String.class);
56 | Method setName = clazz.getMethod("setName", String.class);
57 | Method setCreated = clazz.getMethod("setCreated", long.class);
58 | // try instance:
59 | Object obj = clazz.newInstance();
60 | // get as proxy:
61 | BeanProxy proxy = (BeanProxy) obj;
62 | assertFalse(proxy.isDirty());
63 | // set:
64 | setId.invoke(obj, "A-123");
65 | setName.invoke(obj, "Fly");
66 | setCreated.invoke(obj, 123000999);
67 | // get as user:
68 | User user = (User) obj;
69 | assertEquals("A-123", user.getId());
70 | assertEquals("Fly", user.getName());
71 | assertEquals(123000999, user.getCreated());
72 | assertTrue(proxy.isDirty());
73 | }
74 |
75 | static final String MULTIPLE_JAVA = "/* a single class to many files */ "
76 | + "package on.the.fly; "
77 | + "import java.util.*; "
78 | + "public class Multiple { "
79 | + " List list = new ArrayList(); "
80 | + " public void add(String name) { "
81 | + " Bird bird = new Bird(); "
82 | + " bird.name = name; "
83 | + " this.list.add(bird); "
84 | + " } "
85 | + " public Bird getFirstBird() { "
86 | + " return this.list.get(0); "
87 | + " } "
88 | + " public static class StaticBird { "
89 | + " public int weight = 100; "
90 | + " } "
91 | + " class NestedBird { "
92 | + " NestedBird() { "
93 | + " System.out.println(list.size() + \" birds...\"); "
94 | + " } "
95 | + " } "
96 | + "} "
97 | + "/* package level */ "
98 | + "class Bird { "
99 | + " String name = null; "
100 | + "} ";
101 |
102 | @Test
103 | public void testCompileMultipleClasses() throws Exception {
104 | Map results = compiler.compile("Multiple.java", MULTIPLE_JAVA);
105 | assertEquals(4, results.size());
106 | assertTrue(results.containsKey("on.the.fly.Multiple"));
107 | assertTrue(results.containsKey("on.the.fly.Multiple$StaticBird"));
108 | assertTrue(results.containsKey("on.the.fly.Multiple$NestedBird"));
109 | assertTrue(results.containsKey("on.the.fly.Bird"));
110 | Class> clzMul = compiler.loadClass("on.the.fly.Multiple", results);
111 | // try instance:
112 | Object obj = clzMul.newInstance();
113 | assertNotNull(obj);
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/test/java/com/itranswarp/on/the/fly/BeanProxy.java:
--------------------------------------------------------------------------------
1 | package com.itranswarp.on.the.fly;
2 |
3 | /**
4 | * Sample interface.
5 | *
6 | * @author michael
7 | */
8 | public interface BeanProxy {
9 |
10 | void setDirty(boolean dirty);
11 |
12 | boolean isDirty();
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/test/java/com/itranswarp/on/the/fly/User.java:
--------------------------------------------------------------------------------
1 | package com.itranswarp.on.the.fly;
2 |
3 | /**
4 | * Sample class as JavaBean.
5 | *
6 | * @author michael
7 | */
8 | public class User {
9 |
10 | private String id;
11 | private String name;
12 | private long created;
13 |
14 | public String getId() {
15 | return id;
16 | }
17 |
18 | public void setId(String id) {
19 | this.id = id;
20 | }
21 |
22 | public String getName() {
23 | return name;
24 | }
25 |
26 | public void setName(String name) {
27 | this.name = name;
28 | }
29 |
30 | public long getCreated() {
31 | return created;
32 | }
33 |
34 | public void setCreated(long created) {
35 | this.created = created;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------