Java tutorial
/** * Copyright 2013-2014 Ralph Schaer <ralphschaer@gmail.com> * * 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 ch.rasc.extclassgenerator; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedOptions; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic; import javax.tools.FileObject; import javax.tools.StandardLocation; import org.springframework.util.StringUtils; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; @SupportedAnnotationTypes({ "ch.rasc.extclassgenerator.Model" }) @SupportedOptions({ "outputFormat", "debug", "includeValidation" }) public class ModelAnnotationProcessor extends AbstractProcessor { private static final boolean ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS = false; private static final String OPTION_OUTPUTFORMAT = "outputFormat"; private static final String OPTION_DEBUG = "debug"; private static final String OPTION_INCLUDEVALIDATION = "includeValidation"; private static final String OPTION_CREATEBASEANDSUBCLASS = "createBaseAndSubclass"; private static final String OPTION_USESINGLEQUOTES = "useSingleQuotes"; private static final String OPTION_SURROUNDAPIWITHQUOTES = "surroundApiWithQuotes"; @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { this.processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Running " + getClass().getSimpleName()); if (roundEnv.processingOver() || annotations.size() == 0) { return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS; } if (roundEnv.getRootElements() == null || roundEnv.getRootElements().isEmpty()) { this.processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "No sources to process"); return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS; } OutputConfig outputConfig = new OutputConfig(); outputConfig.setDebug(!"false".equals(this.processingEnv.getOptions().get(OPTION_DEBUG))); boolean createBaseAndSubclass = "true" .equals(this.processingEnv.getOptions().get(OPTION_CREATEBASEANDSUBCLASS)); String outputFormatString = this.processingEnv.getOptions().get(OPTION_OUTPUTFORMAT); outputConfig.setOutputFormat(OutputFormat.EXTJS4); if (StringUtils.hasText(outputFormatString)) { if (OutputFormat.TOUCH2.name().equalsIgnoreCase(outputFormatString)) { outputConfig.setOutputFormat(OutputFormat.TOUCH2); } else if (OutputFormat.EXTJS5.name().equalsIgnoreCase(outputFormatString)) { outputConfig.setOutputFormat(OutputFormat.EXTJS5); } } String includeValidationString = this.processingEnv.getOptions().get(OPTION_INCLUDEVALIDATION); outputConfig.setIncludeValidation(IncludeValidation.NONE); if (StringUtils.hasText(includeValidationString)) { if (IncludeValidation.ALL.name().equalsIgnoreCase(includeValidationString)) { outputConfig.setIncludeValidation(IncludeValidation.ALL); } else if (IncludeValidation.BUILTIN.name().equalsIgnoreCase(includeValidationString)) { outputConfig.setIncludeValidation(IncludeValidation.BUILTIN); } } outputConfig.setUseSingleQuotes("true".equals(this.processingEnv.getOptions().get(OPTION_USESINGLEQUOTES))); outputConfig.setSurroundApiWithQuotes( "true".equals(this.processingEnv.getOptions().get(OPTION_SURROUNDAPIWITHQUOTES))); for (TypeElement annotation : annotations) { Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(annotation); for (Element element : elements) { try { TypeElement typeElement = (TypeElement) element; String qualifiedName = typeElement.getQualifiedName().toString(); Class<?> modelClass = Class.forName(qualifiedName); String code = ModelGenerator.generateJavascript(modelClass, outputConfig); Model modelAnnotation = element.getAnnotation(Model.class); String modelName = modelAnnotation.value(); String fileName; String packageName = ""; if (StringUtils.hasText(modelName)) { int lastDot = modelName.lastIndexOf('.'); if (lastDot != -1) { fileName = modelName.substring(lastDot + 1); int firstDot = modelName.indexOf('.'); if (firstDot < lastDot) { packageName = modelName.substring(firstDot + 1, lastDot); } } else { fileName = modelName; } } else { fileName = typeElement.getSimpleName().toString(); } if (createBaseAndSubclass) { code = code.replaceFirst("(Ext.define\\([\"'].+?)([\"'],)", "$1Base$2"); FileObject fo = this.processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT, packageName, fileName + "Base.js"); OutputStream os = fo.openOutputStream(); os.write(code.getBytes(ModelGenerator.UTF8_CHARSET)); os.close(); try { fo = this.processingEnv.getFiler().getResource(StandardLocation.SOURCE_OUTPUT, packageName, fileName + ".js"); InputStream is = fo.openInputStream(); is.close(); } catch (FileNotFoundException e) { String subClassCode = generateSubclassCode(modelClass, outputConfig); fo = this.processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT, packageName, fileName + ".js"); os = fo.openOutputStream(); os.write(subClassCode.getBytes(ModelGenerator.UTF8_CHARSET)); os.close(); } } else { FileObject fo = this.processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT, packageName, fileName + ".js"); OutputStream os = fo.openOutputStream(); os.write(code.getBytes(ModelGenerator.UTF8_CHARSET)); os.close(); } } catch (ClassNotFoundException e) { this.processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage()); } catch (IOException e) { this.processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage()); } } } return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS; } private static String generateSubclassCode(Class<?> clazz, OutputConfig outputConfig) { Model modelAnnotation = clazz.getAnnotation(Model.class); String name; if (modelAnnotation != null && StringUtils.hasText(modelAnnotation.value())) { name = modelAnnotation.value(); } else { name = clazz.getName(); } Map<String, Object> modelObject = new LinkedHashMap<String, Object>(); modelObject.put("extend", name + "Base"); StringBuilder sb = new StringBuilder(100); sb.append("Ext.define(\"").append(name).append("\","); if (outputConfig.isDebug()) { sb.append("\n"); } String configObjectString; try { ObjectMapper mapper = new ObjectMapper(); mapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false); if (!outputConfig.isSurroundApiWithQuotes()) { if (outputConfig.getOutputFormat() == OutputFormat.EXTJS5) { mapper.addMixInAnnotations(ProxyObject.class, ProxyObjectWithoutApiQuotesExtJs5Mixin.class); } else { mapper.addMixInAnnotations(ProxyObject.class, ProxyObjectWithoutApiQuotesMixin.class); } mapper.addMixInAnnotations(ApiObject.class, ApiObjectMixin.class); } else { if (outputConfig.getOutputFormat() != OutputFormat.EXTJS5) { mapper.addMixInAnnotations(ProxyObject.class, ProxyObjectWithApiQuotesMixin.class); } } if (outputConfig.isDebug()) { configObjectString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(modelObject); } else { configObjectString = mapper.writeValueAsString(modelObject); } } catch (JsonGenerationException e) { throw new RuntimeException(e); } catch (JsonMappingException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } sb.append(configObjectString); sb.append(");"); if (outputConfig.isUseSingleQuotes()) { return sb.toString().replace('"', '\''); } return sb.toString(); } }