Skip to content
This repository was archived by the owner on Feb 26, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Extract custom JCodeModel code into a new class
  • Loading branch information
DayS committed Oct 9, 2012
commit 5121f836c56fc8292e51199637914b8f55752e3c
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package com.googlecode.androidannotations.processing;

import java.util.ArrayList;
import java.util.List;

import com.sun.codemodel.JClass;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JType;

/**
* This class is a decorator of {@link JCodeModel} allowing usage of
* {@link #parseType(String)} and keeping each {@link JClass} found into the
* {@link EBeansHolder} buffer. This is useful for generics definition.
* <p />
* <b>Note</b> : It's a hard-copy of a methods subset of {@link JCodeModel} with
* just one custom line (in {@link TypeNameParser#parseTypeName()} :
*
* <pre>
* JClass clazz = eBeansHolder.uniqueRefClass(s.substring(start, idx));
* </pre>
*
* This solution was needed because JCodeModel is a final class.
*/
public class BufferedJCodeModel {

private final EBeansHolder eBeansHolder;
private final JCodeModel codeModel;

public BufferedJCodeModel(EBeansHolder eBeansHolder, JCodeModel codeModel) {
this.eBeansHolder = eBeansHolder;
this.codeModel = codeModel;
}

/**
* Obtains a type object from a type name.
*
* <p>
* This method handles primitive types, arrays, and existing {@link Class}
* es.
*
* @exception ClassNotFoundException
* If the specified type is not found.
*/
JType parseType(String name) throws ClassNotFoundException {
// array
if (name.endsWith("[]")) {
return parseType(name.substring(0, name.length() - 2)).array();
}

// try primitive type
try {
return JType.parse(codeModel, name);
} catch (IllegalArgumentException e) {
;
}

// existing class
return new TypeNameParser(name).parseTypeName();
}

private final class TypeNameParser {
private final String s;
private int idx;

public TypeNameParser(String s) {
this.s = s;
}

/**
* Parses a type name token T (which can be potentially of the form
* Tr&ly;T1,T2,...>, or "? extends/super T".)
*
* @return the index of the character next to T.
*/
JClass parseTypeName() throws ClassNotFoundException {
int start = idx;

if (s.charAt(idx) == '?') {
// wildcard
idx++;
ws();
String head = s.substring(idx);
if (head.startsWith("extends")) {
idx += 7;
ws();
return parseTypeName().wildcard();
} else if (head.startsWith("super")) {
throw new UnsupportedOperationException("? super T not implemented");
} else {
// not supported
throw new IllegalArgumentException("only extends/super can follow ?, but found " + s.substring(idx));
}
}

while (idx < s.length()) {
char ch = s.charAt(idx);
if (Character.isJavaIdentifierStart(ch) || Character.isJavaIdentifierPart(ch) || ch == '.') {
idx++;
} else {
break;
}
}

JClass clazz = eBeansHolder.uniqueRefClass(s.substring(start, idx));

return parseSuffix(clazz);
}

/**
* Parses additional left-associative suffixes, like type arguments and
* array specifiers.
*/
private JClass parseSuffix(JClass clazz) throws ClassNotFoundException {
if (idx == s.length()) {
return clazz; // hit EOL
}

char ch = s.charAt(idx);

if (ch == '<') {
return parseSuffix(parseArguments(clazz));
}

if (ch == '[') {
if (s.charAt(idx + 1) == ']') {
idx += 2;
return parseSuffix(clazz.array());
}
throw new IllegalArgumentException("Expected ']' but found " + s.substring(idx + 1));
}

return clazz;
}

/**
* Skips whitespaces
*/
private void ws() {
while (Character.isWhitespace(s.charAt(idx)) && idx < s.length()) {
idx++;
}
}

/**
* Parses '&lt;T1,T2,...,Tn>'
*
* @return the index of the character next to '>'
*/
private JClass parseArguments(JClass rawType) throws ClassNotFoundException {
if (s.charAt(idx) != '<') {
throw new IllegalArgumentException();
}
idx++;

List<JClass> args = new ArrayList<JClass>();

while (true) {
args.add(parseTypeName());
if (idx == s.length()) {
throw new IllegalArgumentException("Missing '>' in " + s);
}
char ch = s.charAt(idx);
if (ch == '>') {
return rawType.narrow(args.toArray(new JClass[args.size()]));
}

if (ch != ',') {
throw new IllegalArgumentException(s);
}
idx++;
}

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.lang.model.element.Element;
Expand Down Expand Up @@ -140,12 +138,15 @@ public class Classes {

private final JCodeModel codeModel;

private final BufferedJCodeModel bufferedCodeModel;

private final Map<String, JClass> loadedClasses = new HashMap<String, JClass>();

private final Classes classes;

public EBeansHolder(JCodeModel codeModel) {
this.codeModel = codeModel;
bufferedCodeModel = new BufferedJCodeModel(this, codeModel);
classes = new Classes();
}

Expand Down Expand Up @@ -183,7 +184,7 @@ public JClass refClass(String fullyQualifiedClassName) {
* @param fullyQualifiedClassName
* @return
*/
private JClass uniqueRefClass(String fullyQualifiedClassName) {
JClass uniqueRefClass(String fullyQualifiedClassName) {
JClass refClass = loadedClasses.get(fullyQualifiedClassName);
if (refClass == null) {
refClass = codeModel.ref(fullyQualifiedClassName);
Expand All @@ -204,7 +205,7 @@ public JClass parseClass(String fullyQualifiedClassName) {
JClass refClass = loadedClasses.get(fullyQualifiedClassName);
if (refClass == null) {
try {
JType jType = parseType(fullyQualifiedClassName);
JType jType = bufferedCodeModel.parseType(fullyQualifiedClassName);
if (jType.isPrimitive()) {
refClass = jType.boxify();
}
Expand All @@ -218,33 +219,6 @@ public JClass parseClass(String fullyQualifiedClassName) {
return refClass;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the code implemented in EBeanHolder.parseClass() should rather be implemented here :) .


/**
* Obtains a type object from a type name.
*
* <p>
* This method handles primitive types, arrays, and existing {@link Class}
* es.
*
* @exception ClassNotFoundException
* If the specified type is not found.
*/
private JType parseType(String name) throws ClassNotFoundException {
// array
if (name.endsWith("[]")) {
return parseType(name.substring(0, name.length() - 2)).array();
}

// try primitive type
try {
return JType.parse(codeModel, name);
} catch (IllegalArgumentException e) {
;
}

// existing class
return new TypeNameParser(name).parseTypeName();
}

public JClass refClass(Class<?> clazz) {
return codeModel.ref(clazz);
}
Expand All @@ -257,119 +231,4 @@ public Classes classes() {
return classes;
}

private final class TypeNameParser {
private final String s;
private int idx;

public TypeNameParser(String s) {
this.s = s;
}

/**
* Parses a type name token T (which can be potentially of the form
* Tr&ly;T1,T2,...>, or "? extends/super T".)
*
* @return the index of the character next to T.
*/
JClass parseTypeName() throws ClassNotFoundException {
int start = idx;

if (s.charAt(idx) == '?') {
// wildcard
idx++;
ws();
String head = s.substring(idx);
if (head.startsWith("extends")) {
idx += 7;
ws();
return parseTypeName().wildcard();
} else if (head.startsWith("super")) {
throw new UnsupportedOperationException("? super T not implemented");
} else {
// not supported
throw new IllegalArgumentException("only extends/super can follow ?, but found " + s.substring(idx));
}
}

while (idx < s.length()) {
char ch = s.charAt(idx);
if (Character.isJavaIdentifierStart(ch) || Character.isJavaIdentifierPart(ch) || ch == '.') {
idx++;
} else {
break;
}
}

JClass clazz = uniqueRefClass(s.substring(start, idx));

return parseSuffix(clazz);
}

/**
* Parses additional left-associative suffixes, like type arguments and
* array specifiers.
*/
private JClass parseSuffix(JClass clazz) throws ClassNotFoundException {
if (idx == s.length()) {
return clazz; // hit EOL
}

char ch = s.charAt(idx);

if (ch == '<') {
return parseSuffix(parseArguments(clazz));
}

if (ch == '[') {
if (s.charAt(idx + 1) == ']') {
idx += 2;
return parseSuffix(clazz.array());
}
throw new IllegalArgumentException("Expected ']' but found " + s.substring(idx + 1));
}

return clazz;
}

/**
* Skips whitespaces
*/
private void ws() {
while (Character.isWhitespace(s.charAt(idx)) && idx < s.length()) {
idx++;
}
}

/**
* Parses '&lt;T1,T2,...,Tn>'
*
* @return the index of the character next to '>'
*/
private JClass parseArguments(JClass rawType) throws ClassNotFoundException {
if (s.charAt(idx) != '<') {
throw new IllegalArgumentException();
}
idx++;

List<JClass> args = new ArrayList<JClass>();

while (true) {
args.add(parseTypeName());
if (idx == s.length()) {
throw new IllegalArgumentException("Missing '>' in " + s);
}
char ch = s.charAt(idx);
if (ch == '>') {
return rawType.narrow(args.toArray(new JClass[args.size()]));
}

if (ch != ',') {
throw new IllegalArgumentException(s);
}
idx++;
}

}
}

}