diff options
Diffstat (limited to 'codegen')
8 files changed, 824 insertions, 0 deletions
diff --git a/codegen/pom.xml b/codegen/pom.xml new file mode 100644 index 00000000..c2f9499a --- /dev/null +++ b/codegen/pom.xml @@ -0,0 +1,182 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>com.google.code.gson</groupId> + <artifactId>gson-codegen</artifactId> + <packaging>jar</packaging> + <version>1.0-SNAPSHOT</version> + <inceptionYear>2008</inceptionYear> + <name>Gson Code Gen</name> + <parent> + <groupId>org.sonatype.oss</groupId> + <artifactId>oss-parent</artifactId> + <version>7</version> + </parent> + <url>http://code.google.com/p/google-gson/</url> + <description>Google Gson grab bag of utilities, type adapters, etc.</description> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <licenses> + <license> + <name>The Apache Software License, Version 2.0</name> + <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> + <distribution>repo</distribution> + </license> + </licenses> + <scm> + <connection>scm:svn:http://google-gson.googlecode.com/svn/trunk/extras</connection> + <developerConnection>scm:svn:https://google-gson.googlecode.com/svn/trunk/extras</developerConnection> + <url>http://google-gson.codegoogle.com/svn/trunk/extras</url> + </scm> + <issueManagement> + <system>Google Code Issue Tracking</system> + <url>http://code.google.com/p/google-gson/issues/list</url> + </issueManagement> + <organization> + <name>Google, Inc.</name> + <url>http://www.google.com</url> + </organization> + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>3.8.2</version> + <scope>test</scope> + </dependency> + </dependencies> + <profiles> + <!-- Activate PGP signing only when performing a release --> + <profile> + <id>release-sign-artifacts</id> + <activation> + <property> + <name>performRelease</name> + <value>true</value> + </property> + </activation> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-gpg-plugin</artifactId> + <version>1.4</version> + <executions> + <execution> + <id>sign-artifacts</id> + <phase>verify</phase> + <goals> + <goal>sign</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + </profiles> + <build> + <defaultGoal>package</defaultGoal> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>2.5.1</version> + <configuration> + <source>1.6</source> + <target>1.6</target> + <compilerArgument>-proc:none</compilerArgument> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>2.4</version> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>jar</goal> + </goals> + </execution> + </executions> + <configuration> + <archive> + <addMavenDescriptor>false</addMavenDescriptor> + </archive> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + <version>2.1.2</version> + <executions> + <execution> + <id>attach-sources</id> + <phase>verify</phase> + <goals> + <goal>jar</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <version>2.8.1</version> + <executions> + <execution> + <id>attach-javadocs</id> + <goals> + <goal>jar</goal> + </goals> + </execution> + </executions> + <configuration> + <links> + <link>http://download.oracle.com/javase/1.5.0/docs/api/</link> + </links> + <version>true</version> + <show>public</show> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-eclipse-plugin</artifactId> + <version>2.9</version> + <configuration> + <downloadSources>true</downloadSources> + <downloadJavadocs>true</downloadJavadocs> + <workspace> + ../eclipse-ws/ + </workspace> + <workspaceCodeStylesURL> + file:///${basedir}/../lib/gson-formatting-styles.xml + </workspaceCodeStylesURL> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-release-plugin</artifactId> + <!-- version>2.3.2</version --> + <configuration> + <arguments>-DenableCiProfile=true</arguments> + <tagBase>https://google-gson.googlecode.com/svn/tags/</tagBase> + </configuration> + </plugin> + </plugins> + </build> + <developers> + <developer> + <name>Inderjeet Singh</name> + <organization>Trymph Inc.</organization> + </developer> + <developer> + <name>Joel Leitch</name> + <organization>Google Inc.</organization> + </developer> + <developer> + <name>Jesse Wilson</name> + <organization>Square Inc.</organization> + </developer> + </developers> +</project> diff --git a/codegen/src/main/java/com/google/gson/codegen/CodeGen.java b/codegen/src/main/java/com/google/gson/codegen/CodeGen.java new file mode 100644 index 00000000..011568ff --- /dev/null +++ b/codegen/src/main/java/com/google/gson/codegen/CodeGen.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2012 Square, 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.gson.codegen; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; + +public class CodeGen { + private CodeGen() { + } + + public static PackageElement getPackage(Element type) { + while (type.getKind() != ElementKind.PACKAGE) { + type = type.getEnclosingElement(); + } + return (PackageElement) type; + } + + /** + * Returns a fully qualified class name to complement {@code type}. + */ + public static String adapterName(TypeElement typeElement, String suffix) { + StringBuilder builder = new StringBuilder(); + rawTypeToString(builder, typeElement, '$'); + builder.append(suffix); + return builder.toString(); + } + + static void rawTypeToString(StringBuilder result, TypeElement type, char innerClassSeparator) { + String packageName = getPackage(type).getQualifiedName().toString(); + String qualifiedName = type.getQualifiedName().toString(); + result.append(packageName); + result.append('.'); + result.append( + qualifiedName.substring(packageName.length() + 1).replace('.', innerClassSeparator)); + } +} diff --git a/codegen/src/main/java/com/google/gson/codegen/GeneratedTypeAdapter.java b/codegen/src/main/java/com/google/gson/codegen/GeneratedTypeAdapter.java new file mode 100644 index 00000000..1694d88a --- /dev/null +++ b/codegen/src/main/java/com/google/gson/codegen/GeneratedTypeAdapter.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2012 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.gson.codegen; + +public @interface GeneratedTypeAdapter { + Class<?>[] value() default {}; +} diff --git a/codegen/src/main/java/com/google/gson/codegen/GeneratedTypeAdapterProcessor.java b/codegen/src/main/java/com/google/gson/codegen/GeneratedTypeAdapterProcessor.java new file mode 100644 index 00000000..cd542bc3 --- /dev/null +++ b/codegen/src/main/java/com/google/gson/codegen/GeneratedTypeAdapterProcessor.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2012 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.gson.codegen; + +import static java.lang.reflect.Modifier.FINAL; + +import java.io.IOException; +import java.util.Set; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; + +@SupportedAnnotationTypes("com.google.gson.codegen.GeneratedTypeAdapter") +@SupportedSourceVersion(SourceVersion.RELEASE_6) +public final class GeneratedTypeAdapterProcessor extends AbstractProcessor { + @Override public boolean process(Set<? extends TypeElement> types, RoundEnvironment env) { + System.out.println("invoked GeneratedTypeAdapterProcessor"); + try { + for (Element element : env.getElementsAnnotatedWith(GeneratedTypeAdapter.class)) { + writeAdapter((TypeElement) element); + } + } catch (IOException e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage()); + } + return true; + } + + private void writeAdapter(TypeElement type) throws IOException { + String typeAdapterName = CodeGen.adapterName(type, "$TypeAdapter"); + JavaFileObject sourceFile = processingEnv.getFiler() + .createSourceFile(typeAdapterName, type); + System.out.println("Generating type adapter: " + typeAdapterName + " in " + sourceFile.getName()); + + JavaWriter writer = new JavaWriter(sourceFile.openWriter()); + writer.addPackage(CodeGen.getPackage(type).getQualifiedName().toString()); + writer.beginType(typeAdapterName, "class", FINAL, null); + writer.endType(); + writer.close(); + } +} diff --git a/codegen/src/main/java/com/google/gson/codegen/JavaWriter.java b/codegen/src/main/java/com/google/gson/codegen/JavaWriter.java new file mode 100644 index 00000000..ccba6c8c --- /dev/null +++ b/codegen/src/main/java/com/google/gson/codegen/JavaWriter.java @@ -0,0 +1,443 @@ +/** + * Copyright (C) 2012 Square, 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.gson.codegen; + +import java.io.IOException; +import java.io.Writer; +import java.lang.annotation.Annotation; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Emits Java source files. + */ +public final class JavaWriter { + private static final Pattern TYPE_PATTERN = Pattern.compile("(?:[\\w$]+\\.)*([\\w$]+)"); + private static final String INDENT = " "; + + /** Map fully qualified type names to their short names. */ + private final Map<String, String> importedTypes = new HashMap<String, String>(); + + private String packagePrefix; + private final List<Scope> scopes = new ArrayList<Scope>(); + private final Writer out; + + /** + * @param out the stream to which Java source will be written. This should be + * a buffered stream. + */ + public JavaWriter(Writer out) { + this.out = out; + } + + /** + * Emit a package declaration. + */ + public void addPackage(String packageName) throws IOException { + if (this.packagePrefix != null) { + throw new IllegalStateException(); + } + out.write("package "); + out.write(packageName); + out.write(";\n"); + this.packagePrefix = packageName + "."; + } + + /** + * Equivalent to {@code addImport(type.getName())}. + */ + public void addImport(Class<?> type) throws IOException { + addImport(type.getName()); + } + + /** + * Emit an import for {@code type}. For the duration of the file, all + * references to this class will be automatically shortened. + */ + public void addImport(String type) throws IOException { + Matcher matcher = TYPE_PATTERN.matcher(type); + if (!matcher.matches()) { + throw new IllegalArgumentException(type); + } + if (importedTypes.put(type, matcher.group(1)) != null) { + throw new IllegalArgumentException(type); + } + out.write("import "); + out.write(type); + out.write(";\n"); + } + + /** + * Emits a name like {@code java.lang.String} or {@code + * java.util.List<java.lang.String>}, shorting it with imports if + * possible. + */ + private void type(String type) throws IOException { + if (this.packagePrefix == null) { + throw new IllegalStateException(); + } + + Matcher m = TYPE_PATTERN.matcher(type); + int pos = 0; + while (true) { + boolean found = m.find(pos); + + // copy non-matching characters like "<" + int typeStart = found ? m.start() : type.length(); + out.write(type, pos, typeStart - pos); + + if (!found) { + break; + } + + // copy a single class name, shortening it if possible + String name = m.group(0); + String imported; + if ((imported = importedTypes.get(name)) != null) { + out.write(imported); + } else if (name.startsWith(packagePrefix) + && name.indexOf('.', packagePrefix.length()) == -1) { + out.write(name.substring(packagePrefix.length())); + } else if (name.startsWith("java.lang.")) { + out.write(name.substring("java.lang.".length())); + } else { + out.write(name); + } + pos = m.end(); + } + } + + /** + * Emits a type declaration. + * + * @param kind such as "class", "interface" or "enum". + */ + public void beginType(String type, String kind, int modifiers) throws IOException { + beginType(type, kind, modifiers, null); + } + + /** + * Emits a type declaration. + * + * @param kind such as "class", "interface" or "enum". + * @param extendsType the class to extend, or null for no extends clause. + */ + public void beginType(String type, String kind, int modifiers, + String extendsType, String... implementsTypes) throws IOException { + indent(); + modifiers(modifiers); + out.write(kind); + out.write(" "); + type(type); + if (extendsType != null) { + out.write("\n"); + indent(); + out.write(" extends "); + type(extendsType); + } + if (implementsTypes.length > 0) { + out.write("\n"); + indent(); + out.write(" implements "); + for (int i = 0; i < implementsTypes.length; i++) { + if (i != 0) { + out.write(", "); + } + type(implementsTypes[i]); + } + } + out.write(" {\n"); + pushScope(Scope.TYPE_DECLARATION); + } + + /** + * Completes the current type declaration. + */ + public void endType() throws IOException { + if (popScope() != Scope.TYPE_DECLARATION) { + throw new IllegalStateException(); + } + indent(); + out.write("}\n"); + } + + /** + * Emits a field declaration. + */ + public void field(String type, String name, int modifiers) throws IOException { + field(type, name, modifiers, null); + } + + public void field(String type, String name, int modifiers, String initialValue) + throws IOException { + indent(); + modifiers(modifiers); + type(type); + out.write(" "); + out.write(name); + + if (initialValue != null) { + out.write(" = "); + out.write(initialValue); + } + out.write(";\n"); + } + + /** + * Emit a method declaration. + * + * @param returnType the method's return type, or null for constructors. + * @param parameters alternating parameter types and names. + * @param name the method name, or the fully qualified class name for + * constructors. + */ + public void beginMethod(String returnType, String name, int modifiers, String... parameters) + throws IOException { + indent(); + modifiers(modifiers); + if (returnType != null) { + type(returnType); + out.write(" "); + out.write(name); + } else { + type(name); + } + out.write("("); + for (int p = 0; p < parameters.length; ) { + if (p != 0) { + out.write(", "); + } + type(parameters[p++]); + out.write(" "); + type(parameters[p++]); + } + out.write(")"); + if ((modifiers & Modifier.ABSTRACT) != 0) { + out.write(";\n"); + pushScope(Scope.ABSTRACT_METHOD); + } else { + out.write(" {\n"); + pushScope(Scope.NON_ABSTRACT_METHOD); + } + } + + /** + * Annotates the next element with {@code annotation}. The annotation has no + * attributes. + */ + public void annotation(String annotation) throws IOException { + indent(); + out.write("@"); + type(annotation); + out.write("\n"); + } + + /** + * Equivalent to {@code annotation(annotationType.getName())}. + */ + public void annotation(Class<? extends Annotation> annotationType) throws IOException { + annotation(annotationType.getName()); + } + + /** + * @param pattern a code pattern like "int i = %s". Shouldn't contain a + * trailing semicolon or newline character. + */ + public void statement(String pattern, Object... args) throws IOException { + checkInMethod(); + indent(); + out.write(String.format(pattern, args)); + out.write(";\n"); + } + + /** + * @param controlFlow the control flow construct and its code, such as + * "if (foo == 5)". Shouldn't contain braces or newline characters. + */ + public void beginControlFlow(String controlFlow) throws IOException { + checkInMethod(); + indent(); + out.write(controlFlow); + out.write(" {\n"); + pushScope(Scope.CONTROL_FLOW); + } + + /** + * @param controlFlow the control flow construct and its code, such as + * "else if (foo == 10)". Shouldn't contain braces or newline characters. + */ + public void nextControlFlow(String controlFlow) throws IOException { + if (popScope() != Scope.CONTROL_FLOW) { + throw new IllegalArgumentException(); + } + + indent(); + pushScope(Scope.CONTROL_FLOW); + out.write("} "); + out.write(controlFlow); + out.write(" {\n"); + } + + public void endControlFlow() throws IOException { + endControlFlow(null); + } + + /** + * @param controlFlow the optional control flow construct and its code, such + * as "while(foo == 20)". Only used for "do/while" control flows. + */ + public void endControlFlow(String controlFlow) throws IOException { + if (popScope() != Scope.CONTROL_FLOW) { + throw new IllegalArgumentException(); + } + + indent(); + if (controlFlow != null) { + out.write("} "); + out.write(controlFlow); + out.write(";\n"); + } else { + out.write("}\n"); + } + } + + /** + * Completes the current method declaration. + */ + public void endMethod() throws IOException { + Scope popped = popScope(); + if (popped == Scope.NON_ABSTRACT_METHOD) { + indent(); + out.write("}\n"); + } else if (popped != Scope.ABSTRACT_METHOD) { + throw new IllegalStateException(); + } + } + + /** + * Returns the string literal representing {@code data}, including wrapping + * quotes. + */ + public static String stringLiteral(String data) { + StringBuilder result = new StringBuilder(); + result.append('"'); + for (int i = 0; i < data.length(); i++) { + char c = data.charAt(i); + switch (c) { + case '"': + result.append("\\\""); + break; + case '\\': + result.append("\\\\"); + break; + case '\t': + result.append("\\\t"); + break; + case '\b': + result.append("\\\b"); + break; + case '\n': + result.append("\\\n"); + break; + case '\r': + result.append("\\\r"); + break; + case '\f': + result.append("\\\f"); + break; + default: + result.append(c); + } + } + result.append('"'); + return result.toString(); + } + + public void close() throws IOException { + out.close(); + } + + /** + * Emit modifier names. + */ + private void modifiers(int modifiers) throws IOException { + if ((modifiers & Modifier.PUBLIC) != 0) { + out.write("public "); + } + if ((modifiers & Modifier.PRIVATE) != 0) { + out.write("private "); + } + if ((modifiers & Modifier.PROTECTED) != 0) { + out.write("protected "); + } + if ((modifiers & Modifier.STATIC) != 0) { + out.write("static "); + } + if ((modifiers & Modifier.FINAL) != 0) { + out.write("final "); + } + if ((modifiers & Modifier.ABSTRACT) != 0) { + out.write("abstract "); + } + if ((modifiers & Modifier.SYNCHRONIZED) != 0) { + out.write("synchronized "); + } + if ((modifiers & Modifier.TRANSIENT) != 0) { + out.write("transient "); + } + if ((modifiers & Modifier.VOLATILE) != 0) { + out.write("volatile "); + } + } + + private void indent() throws IOException { + for (int i = 0; i < scopes.size(); i++) { + out.write(INDENT); + } + } + + private void checkInMethod() { + Scope scope = peekScope(); + if (scope != Scope.NON_ABSTRACT_METHOD && scope != Scope.CONTROL_FLOW) { + throw new IllegalArgumentException(); + } + } + + private void pushScope(Scope pushed) { + scopes.add(pushed); + } + + private Scope peekScope() { + return scopes.get(scopes.size() - 1); + } + + private Scope popScope() { + return scopes.remove(scopes.size() - 1); + } + + private enum Scope { + TYPE_DECLARATION, + ABSTRACT_METHOD, + NON_ABSTRACT_METHOD, + CONTROL_FLOW, + } +} diff --git a/codegen/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/codegen/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 00000000..a052da0c --- /dev/null +++ b/codegen/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +com.google.gson.codegen.GeneratedTypeAdapterProcessor
\ No newline at end of file diff --git a/codegen/src/test/java/com/google/gson/codegen/functional/CodeGenFunctionalTest.java b/codegen/src/test/java/com/google/gson/codegen/functional/CodeGenFunctionalTest.java new file mode 100644 index 00000000..855ee3fa --- /dev/null +++ b/codegen/src/test/java/com/google/gson/codegen/functional/CodeGenFunctionalTest.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2012 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.gson.codegen.functional; + +import junit.framework.TestCase; + +public class CodeGenFunctionalTest extends TestCase { + + public void testGeneratedJson() { + Order order = new Order("toy", 10); + // TODO: figure out how to access the generated type adapter + } +} diff --git a/codegen/src/test/java/com/google/gson/codegen/functional/Order.java b/codegen/src/test/java/com/google/gson/codegen/functional/Order.java new file mode 100644 index 00000000..916587f3 --- /dev/null +++ b/codegen/src/test/java/com/google/gson/codegen/functional/Order.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2012 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.gson.codegen.functional; + +import com.google.gson.codegen.GeneratedTypeAdapter; + +@GeneratedTypeAdapter +final class Order { + private final String itemName; + private final int price; + + public Order(String itemName, int price) { + this.itemName = itemName; + this.price = price; + } + + public String getItemName() { + return itemName; + } + + public int getAmount() { + return price; + } +} |