Java tutorial
/** * Mule Development Kit * Copyright 2010-2011 (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.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 org.mule.devkit.module.generation; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.UnhandledException; import org.mule.api.annotations.Configurable; import org.mule.api.annotations.Processor; import org.mule.api.annotations.Source; import org.mule.api.annotations.callback.HttpCallback; import org.mule.api.annotations.callback.InterceptCallback; import org.mule.api.annotations.callback.ProcessorCallback; import org.mule.api.annotations.callback.SourceCallback; import org.mule.api.lifecycle.Disposable; import org.mule.api.lifecycle.Initialisable; import org.mule.config.spring.MuleHierarchicalBeanDefinitionParserDelegate; import org.mule.config.spring.factories.MessageProcessorChainFactoryBean; import org.mule.config.spring.parsers.assembly.BeanAssembler; import org.mule.config.spring.parsers.generic.AutoIdUtils; import org.mule.config.spring.util.SpringXMLUtils; import org.mule.devkit.generation.GenerationException; import org.mule.devkit.model.code.Block; import org.mule.devkit.model.code.CatchBlock; import org.mule.devkit.model.code.Conditional; import org.mule.devkit.model.code.DefinedClass; import org.mule.devkit.model.code.Expression; import org.mule.devkit.model.code.ExpressionFactory; import org.mule.devkit.model.code.ForEach; import org.mule.devkit.model.code.Invocation; import org.mule.devkit.model.code.Method; import org.mule.devkit.model.code.Modifier; import org.mule.devkit.model.code.Op; import org.mule.devkit.model.code.TryStatement; import org.mule.devkit.model.code.Variable; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.PropertyValue; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.support.ManagedMap; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.util.xml.DomUtils; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.ElementFilter; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.StringWriter; import java.util.List; public class BeanDefinitionParserGenerator extends AbstractMessageGenerator { public void generate(Element type) throws GenerationException { generateConfigBeanDefinitionParserFor(type); List<ExecutableElement> executableElements = ElementFilter.methodsIn(type.getEnclosedElements()); for (ExecutableElement executableElement : executableElements) { Processor processor = executableElement.getAnnotation(Processor.class); if (processor == null) continue; generateBeanDefinitionParserForProcessor(executableElement, processor.intercepting()); } for (ExecutableElement executableElement : executableElements) { Source source = executableElement.getAnnotation(Source.class); if (source == null) continue; generateBeanDefinitionParserForSource(executableElement); } } private void generateConfigBeanDefinitionParserFor(Element type) { DefinedClass beanDefinitionparser = getConfigBeanDefinitionParserClass(type); DefinedClass pojo = context .getClassForRole(context.getNameUtils().generateModuleObjectRoleKey((TypeElement) type)); Method parse = beanDefinitionparser.method(Modifier.PUBLIC, ref(BeanDefinition.class), "parse"); Variable element = parse.param(ref(org.w3c.dom.Element.class), "element"); Variable parserContext = parse.param(ref(ParserContext.class), "parserContent"); Variable name = parse.body().decl(ref(String.class), "name", element.invoke("getAttribute").arg("name")); Conditional ifNotNamed = parse.body()._if(Op.cor(Op.eq(name, ExpressionFactory._null()), ref(StringUtils.class).staticInvoke("isBlank").arg(name))); ifNotNamed._then().add(element.invoke("setAttribute").arg("name") .arg(ref(AutoIdUtils.class).staticInvoke("getUniqueName").arg(element).arg("mule-bean"))); Variable builder = parse.body().decl(ref(BeanDefinitionBuilder.class), "builder", ref(BeanDefinitionBuilder.class).staticInvoke("rootBeanDefinition") .arg(pojo.dotclass().invoke("getName"))); Conditional isInitialisable = parse.body() ._if(ref(Initialisable.class).dotclass().invoke("isAssignableFrom").arg(pojo.dotclass())); isInitialisable._then() .add(builder.invoke("setInitMethodName").arg(ref(Initialisable.class).staticRef("PHASE_NAME"))); Conditional isDisposable = parse.body() ._if(ref(Disposable.class).dotclass().invoke("isAssignableFrom").arg(pojo.dotclass())); isDisposable._then() .add(builder.invoke("setDestroyMethodName").arg(ref(Disposable.class).staticRef("PHASE_NAME"))); java.util.List<VariableElement> variables = ElementFilter.fieldsIn(type.getEnclosedElements()); for (VariableElement variable : variables) { Configurable configurable = variable.getAnnotation(Configurable.class); if (configurable == null) continue; String fieldName = variable.getSimpleName().toString(); if (SchemaTypeConversion.isSupported(variable.asType().toString())) { generateParseSupportedType(parse.body(), element, builder, fieldName); } else if (context.getTypeMirrorUtils().isXmlType(variable.asType())) { generateParseXmlType(parse.body(), element, builder, fieldName); } else if (context.getTypeMirrorUtils().isArrayOrList(variable.asType())) { Variable listElement = parse.body().decl(ref(org.w3c.dom.Element.class), fieldName + "ListElement", ExpressionFactory._null()); parse.body().assign(listElement, ref(DomUtils.class).staticInvoke("getChildElementByTagName") .arg(element).arg(context.getNameUtils().uncamel(fieldName))); UpperBlockClosure managedList = generateParseArrayOrList(parse.body(), variable.asType(), listElement, builder, fieldName, parserContext); managedList.getNotRefBlock().add( builder.invoke("addPropertyValue").arg(fieldName).arg(managedList.getManagedCollection())); } else if (context.getTypeMirrorUtils().isMap(variable.asType())) { Variable listElement = parse.body().decl(ref(org.w3c.dom.Element.class), fieldName + "ListElement", ExpressionFactory._null()); parse.body().assign(listElement, ref(DomUtils.class).staticInvoke("getChildElementByTagName") .arg(element).arg(context.getNameUtils().uncamel(fieldName))); UpperBlockClosure managedMap = generateParseMap(parse.body(), variable.asType(), listElement, builder, fieldName, parserContext); managedMap.getNotRefBlock().add( builder.invoke("addPropertyValue").arg(fieldName).arg(managedMap.getManagedCollection())); } else if (context.getTypeMirrorUtils().isEnum(variable.asType())) { generateParseEnum(parse.body(), element, builder, fieldName); } } Variable definition = parse.body().decl(ref(BeanDefinition.class), "definition", builder.invoke("getBeanDefinition")); parse.body() .add(definition.invoke("setAttribute") .arg(ref(MuleHierarchicalBeanDefinitionParserDelegate.class).staticRef("MULE_NO_RECURSE")) .arg(ref(Boolean.class).staticRef("TRUE"))); parse.body()._return(definition); } private void generateBeanDefinitionParserForSource(ExecutableElement executableElement) { // get class DefinedClass beanDefinitionparser = getBeanDefinitionParserClass(executableElement); DefinedClass messageSourceClass = getMessageSourceClass(executableElement); generateSourceParseMethod(beanDefinitionparser, messageSourceClass, executableElement); generateGenerateChildBeanNameMethod(beanDefinitionparser); } private void generateGetBeanClass(DefinedClass beanDefinitionparser, Expression expr) { Method getBeanClass = beanDefinitionparser.method(Modifier.PROTECTED, ref(Class.class), "getBeanClass"); Variable element = getBeanClass.param(ref(org.w3c.dom.Element.class), "element"); getBeanClass.body()._return(expr); } private void generateBeanDefinitionParserForProcessor(ExecutableElement executableElement, boolean intercepting) { DefinedClass beanDefinitionparser = getBeanDefinitionParserClass(executableElement); DefinedClass messageProcessorClass = null; if (intercepting) { messageProcessorClass = getInterceptingMessageProcessorClass(executableElement); } else { messageProcessorClass = getMessageProcessorClass(executableElement); } generateProcessorParseMethod(beanDefinitionparser, messageProcessorClass, executableElement); generateGenerateChildBeanNameMethod(beanDefinitionparser); } private void generateProcessorParseMethod(DefinedClass beanDefinitionparser, DefinedClass messageProcessorClass, ExecutableElement executableElement) { Method parse = beanDefinitionparser.method(Modifier.PUBLIC, ref(BeanDefinition.class), "parse"); Variable element = parse.param(ref(org.w3c.dom.Element.class), "element"); Variable parserContext = parse.param(ref(ParserContext.class), "parserContent"); Variable definition = generateParseCommon(beanDefinitionparser, messageProcessorClass, executableElement, parse, element, parserContext); generateAttachMessageProcessor(parse, definition, parserContext); parse.body()._return(definition); } private void generateSourceParseMethod(DefinedClass beanDefinitionparser, DefinedClass messageProcessorClass, ExecutableElement executableElement) { Method parse = beanDefinitionparser.method(Modifier.PUBLIC, ref(BeanDefinition.class), "parse"); Variable element = parse.param(ref(org.w3c.dom.Element.class), "element"); Variable parserContext = parse.param(ref(ParserContext.class), "parserContent"); Variable definition = generateParseCommon(beanDefinitionparser, messageProcessorClass, executableElement, parse, element, parserContext); generateAttachMessageSource(parse, definition, parserContext); parse.body()._return(definition); } private Variable generateParseCommon(DefinedClass beanDefinitionparser, DefinedClass messageProcessorClass, ExecutableElement executableElement, Method parse, Variable element, Variable parserContext) { Variable builder = parse.body().decl(ref(BeanDefinitionBuilder.class), "builder", ref(BeanDefinitionBuilder.class).staticInvoke("rootBeanDefinition") .arg(messageProcessorClass.dotclass().invoke("getName"))); Conditional isInitialisable = parse.body()._if(ref(Initialisable.class).dotclass() .invoke("isAssignableFrom").arg(messageProcessorClass.dotclass())); isInitialisable._then() .add(builder.invoke("setInitMethodName").arg(ref(Initialisable.class).staticRef("PHASE_NAME"))); Conditional isDisposable = parse.body()._if( ref(Disposable.class).dotclass().invoke("isAssignableFrom").arg(messageProcessorClass.dotclass())); isDisposable._then() .add(builder.invoke("setDestroyMethodName").arg(ref(Disposable.class).staticRef("PHASE_NAME"))); Variable configRef = parse.body().decl(ref(String.class), "configRef", element.invoke("getAttribute").arg("config-ref")); Conditional ifConfigRef = parse.body()._if(Op.cand(Op.ne(configRef, ExpressionFactory._null()), Op.not(ref(StringUtils.class).staticInvoke("isBlank").arg(configRef)))); ifConfigRef._then().add(builder.invoke("addPropertyValue").arg("moduleObject") .arg(ExpressionFactory._new(ref(RuntimeBeanReference.class)).arg(configRef))); Method getAttributeValue = generateGetAttributeValue(beanDefinitionparser); for (VariableElement variable : executableElement.getParameters()) { if (variable.asType().toString().contains(SourceCallback.class.getName())) { continue; } if (variable.asType().toString().contains(InterceptCallback.class.getName())) { continue; } String fieldName = variable.getSimpleName().toString(); if (variable.asType().toString().contains(ProcessorCallback.class.getName())) { generateParseProcessorCallback(parse.body(), element, parserContext, builder, fieldName); } else if (SchemaTypeConversion.isSupported(variable.asType().toString())) { generateParseSupportedType(parse.body(), element, builder, fieldName); } else if (context.getTypeMirrorUtils().isTransferObject(variable.asType())) { Variable transferObjectElement = parse.body().decl(ref(org.w3c.dom.Element.class), fieldName + "TransferObjectElement", ExpressionFactory._null()); parse.body().assign(transferObjectElement, ref(DomUtils.class).staticInvoke("getChildElementByTagName").arg(element) .arg(context.getNameUtils().uncamel(fieldName))); Variable beanDefinitionBuilder = generateParseTransferObject(variable.asType(), parse.body(), transferObjectElement, parserContext); parse.body().add(builder.invoke("addPropertyValue").arg(fieldName) .arg(beanDefinitionBuilder.invoke("getBeanDefinition"))); } else if (context.getTypeMirrorUtils().isXmlType(variable.asType())) { generateParseXmlType(parse.body(), element, builder, fieldName); } else if (context.getTypeMirrorUtils().isArrayOrList(variable.asType())) { Variable listElement = parse.body().decl(ref(org.w3c.dom.Element.class), fieldName + "ListElement", ExpressionFactory._null()); parse.body().assign(listElement, ref(DomUtils.class).staticInvoke("getChildElementByTagName") .arg(element).arg(context.getNameUtils().uncamel(fieldName))); UpperBlockClosure managedList = generateParseArrayOrList(parse.body(), variable.asType(), listElement, builder, fieldName, parserContext); managedList.getNotRefBlock().add( builder.invoke("addPropertyValue").arg(fieldName).arg(managedList.getManagedCollection())); } else if (context.getTypeMirrorUtils().isMap(variable.asType())) { Variable listElement = parse.body().decl(ref(org.w3c.dom.Element.class), fieldName + "ListElement", ExpressionFactory._null()); parse.body().assign(listElement, ref(DomUtils.class).staticInvoke("getChildElementByTagName") .arg(element).arg(context.getNameUtils().uncamel(fieldName))); UpperBlockClosure managedMap = generateParseMap(parse.body(), variable.asType(), listElement, builder, fieldName, parserContext); managedMap.getNotRefBlock().add( builder.invoke("addPropertyValue").arg(fieldName).arg(managedMap.getManagedCollection())); } else if (context.getTypeMirrorUtils().isEnum(variable.asType())) { generateParseEnum(parse.body(), element, builder, fieldName); } else if (variable.asType().toString().contains(HttpCallback.class.getName())) { Variable callbackFlowName = parse.body().decl(ref(String.class), fieldName + "CallbackFlowName", ExpressionFactory.invoke(getAttributeValue).arg(element) .arg(context.getNameUtils().uncamel(fieldName) + "-flow-ref")); Block block = parse.body()._if(Op.ne(callbackFlowName, ExpressionFactory._null()))._then(); block.invoke(builder, "addPropertyValue").arg(fieldName + "CallbackFlow") .arg(ExpressionFactory._new(ref(RuntimeBeanReference.class)).arg(callbackFlowName)); } } Variable definition = parse.body().decl(ref(BeanDefinition.class), "definition", builder.invoke("getBeanDefinition")); parse.body() .add(definition.invoke("setAttribute") .arg(ref(MuleHierarchicalBeanDefinitionParserDelegate.class).staticRef("MULE_NO_RECURSE")) .arg(ref(Boolean.class).staticRef("TRUE"))); return definition; } private void generateParseProcessorCallback(Block block, Variable element, Variable parserContext, Variable builder, String fieldName) { Variable elements = block.decl(ref(org.w3c.dom.Element.class), fieldName + "Element", ref(DomUtils.class).staticInvoke("getChildElementByTagName").arg(element) .arg(context.getNameUtils().uncamel(fieldName))); Conditional ifNotNull = block._if(Op.ne(elements, ExpressionFactory._null())); Variable beanDefinitionBuilder = ifNotNull._then().decl(ref(BeanDefinitionBuilder.class), fieldName + "BeanDefinitionBuilder", ref(BeanDefinitionBuilder.class).staticInvoke("rootBeanDefinition") .arg(ref(MessageProcessorChainFactoryBean.class).dotclass())); //ifNotNull._then().add(beanDefinitionBuilder.invoke("setInitMethodName").arg(ref(Initialisable.class).staticRef("PHASE_NAME"))); //ifNotNull._then().add(beanDefinitionBuilder.invoke("setDestroyMethodName").arg(ref(Disposable.class).staticRef("PHASE_NAME"))); Variable beanDefinition = ifNotNull._then().decl(ref(BeanDefinition.class), fieldName + "BeanDefinition", beanDefinitionBuilder.invoke("getBeanDefinition")); ifNotNull._then().add(parserContext.invoke("getRegistry").invoke("registerBeanDefinition") .arg(ExpressionFactory.invoke("generateChildBeanName").arg(elements)).arg(beanDefinition)); ifNotNull._then().add(elements.invoke("setAttribute").arg("name") .arg(ExpressionFactory.invoke("generateChildBeanName").arg(elements))); ifNotNull._then().add( beanDefinitionBuilder.invoke("setSource").arg(parserContext.invoke("extractSource").arg(elements))); ifNotNull._then().add(beanDefinitionBuilder.invoke("setScope") .arg(ref(BeanDefinition.class).staticRef("SCOPE_SINGLETON"))); Variable list = ifNotNull._then().decl(ref(List.class), fieldName + "List", parserContext.invoke("getDelegate").invoke("parseListElement").arg(elements) .arg(beanDefinitionBuilder.invoke("getBeanDefinition"))); ifNotNull._then().add(parserContext.invoke("getRegistry").invoke("removeBeanDefinition") .arg(ExpressionFactory.invoke("generateChildBeanName").arg(elements))); ifNotNull._then().add(builder.invoke("addPropertyValue").arg(fieldName).arg(beanDefinition)); } private void generateParseXmlType(Block block, Variable element, Variable builder, String fieldName) { Variable xmlElement = block.decl(ref(org.w3c.dom.Element.class), fieldName + "xmlElement", ExpressionFactory._null()); block.assign(xmlElement, ref(DomUtils.class).staticInvoke("getChildElementByTagName").arg(element) .arg(context.getNameUtils().uncamel(fieldName))); Conditional xmlElementNotNull = block._if(Op.ne(xmlElement, ExpressionFactory._null())); TryStatement tryBlock = xmlElementNotNull._then()._try(); Variable xmlElementChilds = tryBlock.body().decl(ref(List.class).narrow(org.w3c.dom.Element.class), "xmlElementChilds", ref(DomUtils.class).staticInvoke("getChildElements").arg(xmlElement)); Conditional xmlElementChildsNotEmpty = tryBlock.body() ._if(Op.gt(xmlElementChilds.invoke("size"), ExpressionFactory.lit(0))); Variable domSource = xmlElementChildsNotEmpty._then().decl(ref(DOMSource.class), "domSource", ExpressionFactory._new(ref(DOMSource.class)) .arg(xmlElementChilds.invoke("get").arg(ExpressionFactory.lit(0)))); Variable stringWriter = xmlElementChildsNotEmpty._then().decl(ref(StringWriter.class), "stringWriter", ExpressionFactory._new(ref(StringWriter.class))); Variable streamResult = xmlElementChildsNotEmpty._then().decl(ref(StreamResult.class), "result", ExpressionFactory._new(ref(StreamResult.class)).arg(stringWriter)); Variable tf = xmlElementChildsNotEmpty._then().decl(ref(TransformerFactory.class), "tf", ref(TransformerFactory.class).staticInvoke("newInstance")); Variable transformer = xmlElementChildsNotEmpty._then().decl(ref(Transformer.class), "transformer", tf.invoke("newTransformer")); Invocation transform = transformer.invoke("transform"); transform.arg(domSource); transform.arg(streamResult); xmlElementChildsNotEmpty._then().add(transform); xmlElementChildsNotEmpty._then().add(stringWriter.invoke("flush")); xmlElementChildsNotEmpty._then() .add(builder.invoke("addPropertyValue").arg(fieldName).arg(stringWriter.invoke("toString"))); generateReThrow(tryBlock, TransformerConfigurationException.class); generateReThrow(tryBlock, TransformerException.class); generateReThrow(tryBlock, TransformerFactoryConfigurationError.class); } private void generateReThrow(TryStatement tryBlock, Class<?> clazz) { CatchBlock catchBlock = tryBlock._catch(ref(clazz).boxify()); Variable e = catchBlock.param("e"); catchBlock.body()._throw(ExpressionFactory._new(ref(UnhandledException.class)).arg(e)); } private void generateParseSupportedType(Block block, Variable element, Variable builder, String fieldName) { Invocation getAttribute = element.invoke("getAttribute").arg(fieldName); Conditional ifNotNull = block._if(Op.cand(Op.ne(getAttribute, ExpressionFactory._null()), Op.not(ref(StringUtils.class).staticInvoke("isBlank").arg(getAttribute)))); ifNotNull._then().add(builder.invoke("addPropertyValue").arg(fieldName) .arg(element.invoke("getAttribute").arg(fieldName))); } private void generateParseEnum(Block block, Variable element, Variable builder, String fieldName) { block.add(builder.invoke("addPropertyValue").arg(fieldName) .arg(element.invoke("getAttribute").arg(fieldName))); } private UpperBlockClosure generateParseMap(Block body, TypeMirror typeMirror, Variable listElement, Variable builder, String fieldName, Variable parserContext) { DeclaredType variableType = (DeclaredType) typeMirror; java.util.List<? extends TypeMirror> variableTypeParameters = variableType.getTypeArguments(); Variable listChilds = body.decl(ref(List.class).narrow(ref(org.w3c.dom.Element.class)), fieldName.replace("-", "") + "ListChilds", ExpressionFactory._null()); Conditional listElementNotNull = body._if(Op.ne(listElement, ExpressionFactory._null())); Invocation getElementRef = listElement.invoke("getAttribute").arg("ref"); Variable ref = listElementNotNull._then().decl(ref(String.class), fieldName.replace("-", "") + "Ref", getElementRef); Conditional ifRef = listElementNotNull._then()._if(Op.cand(Op.ne(ref, ExpressionFactory._null()), Op.not(ref(StringUtils.class).staticInvoke("isBlank").arg(ref)))); ifRef._then().add(builder.invoke("addPropertyValue").arg(fieldName) .arg(ExpressionFactory._new(ref(RuntimeBeanReference.class)).arg(ref))); Variable managedMap = ifRef._else().decl(ref(ManagedMap.class), fieldName.replace("-", ""), ExpressionFactory._new(ref(ManagedMap.class))); ifRef._else().assign(listChilds, ref(DomUtils.class).staticInvoke("getChildElementsByTagName").arg(listElement) .arg(context.getNameUtils().uncamel(context.getNameUtils().singularize(fieldName)))); String childName = context.getNameUtils().uncamel(context.getNameUtils().singularize(fieldName)); Conditional listChildsNotNull = ifRef._else()._if(Op.ne(listChilds, ExpressionFactory._null())); Conditional isListEmpty = listChildsNotNull._then() ._if(Op.eq(listChilds.invoke("size"), ExpressionFactory.lit(0))); isListEmpty._then().assign(listChilds, ref(DomUtils.class).staticInvoke("getChildElements").arg(listElement)); ForEach forEach = listChildsNotNull._then().forEach(ref(org.w3c.dom.Element.class), fieldName.replace("-", "") + "Child", listChilds); Invocation getValueRef = forEach.var().invoke("getAttribute").arg("value-ref"); Invocation getKeyRef = forEach.var().invoke("getAttribute").arg("key-ref"); Variable valueRef = forEach.body().decl(ref(String.class), fieldName.replace("-", "") + "ValueRef", getValueRef); Variable keyRef = forEach.body().decl(ref(String.class), fieldName.replace("-", "") + "KeyRef", getKeyRef); Variable valueObject = forEach.body().decl(ref(Object.class), "valueObject", ExpressionFactory._null()); Variable keyObject = forEach.body().decl(ref(Object.class), "keyObject", ExpressionFactory._null()); Conditional ifValueRef = forEach.body()._if(Op.cand(Op.ne(valueRef, ExpressionFactory._null()), Op.not(ref(StringUtils.class).staticInvoke("isBlank").arg(valueRef)))); ifValueRef._then().assign(valueObject, ExpressionFactory._new(ref(RuntimeBeanReference.class)).arg(valueRef)); if (variableTypeParameters.size() > 1 && context.getTypeMirrorUtils().isTransferObject(variableTypeParameters.get(1))) { Variable pojoBuilder = generateParseTransferObject(variableTypeParameters.get(1), ifValueRef._else(), forEach.var(), parserContext); ifValueRef._else().assign(valueObject, pojoBuilder.invoke("getBeanDefinition")); } else if (variableTypeParameters.size() > 1 && context.getTypeMirrorUtils().isArrayOrList(variableTypeParameters.get(1))) { UpperBlockClosure subList = generateParseArrayOrList(forEach.body(), variableTypeParameters.get(1), forEach.var(), builder, "inner-" + childName, parserContext); subList.getNotRefBlock().assign(valueObject, subList.getManagedCollection()); } else if (variableTypeParameters.size() > 1 && context.getTypeMirrorUtils().isMap(variableTypeParameters.get(1))) { UpperBlockClosure subMap = generateParseMap(forEach.body(), variableTypeParameters.get(1), forEach.var(), builder, "inner-" + childName, parserContext); subMap.getNotRefBlock().assign(valueObject, subMap.getManagedCollection()); } else { ifValueRef._else().assign(valueObject, forEach.var().invoke("getTextContent")); } Conditional ifKeyRef = forEach.body()._if(Op.cand(Op.ne(keyRef, ExpressionFactory._null()), Op.not(ref(StringUtils.class).staticInvoke("isBlank").arg(keyRef)))); ifKeyRef._then().assign(keyObject, ExpressionFactory._new(ref(RuntimeBeanReference.class)).arg(keyRef)); ifKeyRef._else().assign(keyObject, forEach.var().invoke("getAttribute").arg("key")); Conditional noKey = forEach.body() ._if(Op.cor(Op.eq(keyObject, ExpressionFactory._null()), Op.cand(Op._instanceof(keyObject, ref(String.class)), ref(StringUtils.class).staticInvoke("isBlank") .arg(ExpressionFactory.cast(ref(String.class), keyObject))))); noKey._then().assign(keyObject, forEach.var().invoke("getTagName")); forEach.body().add(managedMap.invoke("put").arg(keyObject).arg(valueObject)); return new UpperBlockClosure(managedMap, ifRef._else()); } private UpperBlockClosure generateParseArrayOrList(Block body, TypeMirror typeMirror, Variable listElement, Variable builder, String fieldName, Variable parserContext) { DeclaredType variableType = (DeclaredType) typeMirror; java.util.List<? extends TypeMirror> variableTypeParameters = variableType.getTypeArguments(); Variable listChilds = body.decl(ref(List.class).narrow(ref(org.w3c.dom.Element.class)), fieldName.replace("-", "") + "ListChilds", ExpressionFactory._null()); Conditional listElementNotNull = body._if(Op.ne(listElement, ExpressionFactory._null())); Invocation getElementRef = listElement.invoke("getAttribute").arg("ref"); Variable ref = listElementNotNull._then().decl(ref(String.class), fieldName.replace("-", "") + "Ref", getElementRef); Conditional ifRef = listElementNotNull._then()._if(Op.cand(Op.ne(ref, ExpressionFactory._null()), Op.not(ref(StringUtils.class).staticInvoke("isBlank").arg(ref)))); ifRef._then().add(builder.invoke("addPropertyValue").arg(fieldName) .arg(ExpressionFactory._new(ref(RuntimeBeanReference.class)).arg(ref))); Variable managedList = ifRef._else().decl(ref(ManagedList.class), fieldName.replace("-", ""), ExpressionFactory._new(ref(ManagedList.class))); String childName = context.getNameUtils().uncamel(context.getNameUtils().singularize(fieldName)); ifRef._else().assign(listChilds, ref(DomUtils.class).staticInvoke("getChildElementsByTagName").arg(listElement).arg(childName)); Conditional listChildsNotNull = ifRef._else()._if(Op.ne(listChilds, ExpressionFactory._null())); ForEach forEach = listChildsNotNull._then().forEach(ref(org.w3c.dom.Element.class), fieldName.replace("-", "") + "Child", listChilds); Invocation getValueRef = forEach.var().invoke("getAttribute").arg("value-ref"); Variable valueRef = forEach.body().decl(ref(String.class), "valueRef", getValueRef); Conditional ifValueRef = forEach.body()._if(Op.cand(Op.ne(valueRef, ExpressionFactory._null()), Op.not(ref(StringUtils.class).staticInvoke("isBlank").arg(valueRef)))); ifValueRef._then().add(managedList.invoke("add") .arg(ExpressionFactory._new(ref(RuntimeBeanReference.class)).arg(valueRef))); if (variableTypeParameters.size() > 0 && context.getTypeMirrorUtils().isTransferObject(variableTypeParameters.get(0))) { Variable pojoBeanDefinitionBuilder = generateParseTransferObject(variableTypeParameters.get(0), ifValueRef._else(), forEach.var(), parserContext); ifValueRef._else() .add(managedList.invoke("add").arg(pojoBeanDefinitionBuilder.invoke("getBeanDefinition"))); } else if (variableTypeParameters.size() > 0 && context.getTypeMirrorUtils().isArrayOrList(variableTypeParameters.get(0))) { UpperBlockClosure subList = generateParseArrayOrList(ifValueRef._else(), variableTypeParameters.get(0), forEach.var(), builder, "inner-" + childName, parserContext); subList.getNotRefBlock().add(managedList.invoke("add").arg(subList.getManagedCollection())); } else if (variableTypeParameters.size() > 0 && context.getTypeMirrorUtils().isMap(variableTypeParameters.get(0))) { UpperBlockClosure subMap = generateParseMap(ifValueRef._else(), variableTypeParameters.get(0), forEach.var(), builder, "inner-" + childName, parserContext); subMap.getNotRefBlock().add(managedList.invoke("add").arg(subMap.getManagedCollection())); } else { ifValueRef._else().add(managedList.invoke("add").arg(forEach.var().invoke("getTextContent"))); } return new UpperBlockClosure(managedList, ifRef._else()); } private Variable generateParseTransferObject(TypeMirror transferObjectType, Block block, Variable element, Variable parserContext) { DeclaredType declaredType = (DeclaredType) transferObjectType; String baseName = declaredType.asElement().getSimpleName().toString().toLowerCase(); Variable builder = block.decl(ref(BeanDefinitionBuilder.class), baseName + "BeanDefinitionBuilder", ref(BeanDefinitionBuilder.class).staticInvoke("rootBeanDefinition") .arg(ref(transferObjectType).boxify().dotclass())); TypeElement typeElement = (TypeElement) declaredType.asElement(); java.util.List<VariableElement> variables = ElementFilter.fieldsIn(typeElement.getEnclosedElements()); for (VariableElement variable : variables) { String fieldName = variable.getSimpleName().toString(); if (SchemaTypeConversion.isSupported(variable.asType().toString())) { generateParseSupportedType(block, element, builder, fieldName); } else if (variable.asType().toString().contains(ProcessorCallback.class.getName())) { generateParseProcessorCallback(block, element, parserContext, builder, fieldName); } else if (context.getTypeMirrorUtils().isXmlType(variable.asType())) { generateParseXmlType(block, element, builder, fieldName); } else if (context.getTypeMirrorUtils().isArrayOrList(variable.asType())) { Variable listElement = block.decl(ref(org.w3c.dom.Element.class), fieldName + "ListElement", ExpressionFactory._null()); block.assign(listElement, ref(DomUtils.class).staticInvoke("getChildElementByTagName").arg(element) .arg(context.getNameUtils().uncamel(fieldName))); UpperBlockClosure managedList = generateParseArrayOrList(block, variable.asType(), listElement, builder, fieldName, parserContext); managedList.getNotRefBlock().add( builder.invoke("addPropertyValue").arg(fieldName).arg(managedList.getManagedCollection())); } else if (context.getTypeMirrorUtils().isMap(variable.asType())) { Variable listElement = block.decl(ref(org.w3c.dom.Element.class), fieldName + "ListElement", ExpressionFactory._null()); block.assign(listElement, ref(DomUtils.class).staticInvoke("getChildElementByTagName").arg(element) .arg(context.getNameUtils().uncamel(fieldName))); UpperBlockClosure managedMap = generateParseMap(block, variable.asType(), listElement, builder, fieldName, parserContext); managedMap.getNotRefBlock().add( builder.invoke("addPropertyValue").arg(fieldName).arg(managedMap.getManagedCollection())); } else if (context.getTypeMirrorUtils().isEnum(variable.asType())) { generateParseEnum(block, element, builder, fieldName); } } return builder; } private void generateAttachMessageProcessor(Method parse, Variable definition, Variable parserContext) { Variable propertyValues = parse.body().decl(ref(MutablePropertyValues.class), "propertyValues", parserContext.invoke("getContainingBeanDefinition").invoke("getPropertyValues")); Variable messageProcessors = parse.body().decl(ref(PropertyValue.class), "messageProcessors", propertyValues.invoke("getPropertyValue").arg("messageProcessors")); Conditional noList = parse.body()._if(Op.cor(Op.eq(messageProcessors, ExpressionFactory._null()), Op.eq(messageProcessors.invoke("getValue"), ExpressionFactory._null()))); noList._then().add(propertyValues.invoke("addPropertyValue").arg("messageProcessors") .arg(ExpressionFactory._new(ref(ManagedList.class)))); Variable listMessageProcessors = parse.body().decl(ref(List.class), "listMessageProcessors", ExpressionFactory.cast(ref(List.class), propertyValues.invoke("getPropertyValue").arg("messageProcessors").invoke("getValue"))); parse.body().add(listMessageProcessors.invoke("add").arg(definition)); } private void generateAttachMessageSource(Method parse, Variable definition, Variable parserContext) { Variable propertyValues = parse.body().decl(ref(MutablePropertyValues.class), "propertyValues", parserContext.invoke("getContainingBeanDefinition").invoke("getPropertyValues")); parse.body().add(propertyValues.invoke("addPropertyValue").arg("messageSource").arg(definition)); } private void generateGenerateChildBeanNameMethod(DefinedClass beanDefinitionparser) { Method generateChildBeanName = beanDefinitionparser.method(Modifier.PRIVATE, ref(String.class), "generateChildBeanName"); Variable element = generateChildBeanName.param(ref(org.w3c.dom.Element.class), "element"); Variable id = generateChildBeanName.body().decl(ref(String.class), "id", ref(SpringXMLUtils.class).staticInvoke("getNameOrId").arg(element)); Conditional isBlank = generateChildBeanName.body() ._if(ref(StringUtils.class).staticInvoke("isBlank").arg(id)); Invocation getParentName = ref(SpringXMLUtils.class).staticInvoke("getNameOrId") .arg(ExpressionFactory.cast(ref(org.w3c.dom.Element.class), element.invoke("getParentNode"))); Variable parentId = isBlank._then().decl(ref(String.class), "parentId", getParentName); isBlank._then() ._return(Op.plus(Op.plus(Op.plus(ExpressionFactory.lit("."), parentId), ExpressionFactory.lit(":")), element.invoke("getLocalName"))); isBlank._else()._return(id); } private Method generateGetAttributeValue(DefinedClass beanDefinitionparser) { Method getAttributeValue = beanDefinitionparser.method(Modifier.PROTECTED, ref(String.class), "getAttributeValue"); Variable element = getAttributeValue.param(ref(org.w3c.dom.Element.class), "element"); Variable attributeName = getAttributeValue.param(ref(String.class), "attributeName"); Invocation getAttribute = element.invoke("getAttribute").arg(attributeName); Invocation isEmpty = ref(StringUtils.class).staticInvoke("isEmpty"); isEmpty.arg(getAttribute); Block ifIsEmpty = getAttributeValue.body()._if(isEmpty.not())._then(); ifIsEmpty._return(getAttribute); getAttributeValue.body()._return(ExpressionFactory._null()); return getAttributeValue; } private void generateParseChild(DefinedClass beanDefinitionparser, ExecutableElement executableElement) { Method parseChild = beanDefinitionparser.method(Modifier.PROTECTED, context.getCodeModel().VOID, "parseChild"); Variable element = parseChild.param(ref(org.w3c.dom.Element.class), "element"); Variable parserContext = parseChild.param(ref(ParserContext.class), "parserContext"); Variable beanDefinitionBuilder = parseChild.param(ref(BeanDefinitionBuilder.class), "beanDefinitionBuilder"); generateSetPojoIfConfigRefNotEmpty(parseChild, element, beanDefinitionBuilder); for (VariableElement variable : executableElement.getParameters()) { if (variable.asType().toString().contains(SourceCallback.class.getName())) continue; if (SchemaTypeConversion.isSupported(variable.asType().toString()) || context.getTypeMirrorUtils().isEnum(variable.asType())) { parseChild.body().add(generateAddPropertyValue(element, beanDefinitionBuilder, variable)); } } Variable assembler = generateBeanAssembler(parseChild, element, beanDefinitionBuilder); generatePostProcessCall(parseChild, element, assembler); } private void generateSetPojoIfConfigRefNotEmpty(Method parseChild, Variable element, Variable beanDefinitionBuilder) { Conditional isConfigRefEmpty = parseChild.body()._if(Op.not(generateIsEmptyConfigRef(element))); Invocation addPropertyReference = beanDefinitionBuilder.invoke("addPropertyReference"); addPropertyReference.arg("pojo"); Invocation getAttributeAlias = generateGetAttributeConfigRef(); Invocation getAttribute = element.invoke("getAttribute"); getAttribute.arg(getAttributeAlias); addPropertyReference.arg(getAttribute); isConfigRefEmpty._then().add(addPropertyReference); } private Invocation generateIsEmptyConfigRef(Variable element) { Invocation getAttributeAlias = generateGetAttributeConfigRef(); Invocation getAttribute = element.invoke("getAttribute"); getAttribute.arg(getAttributeAlias); Invocation isEmpty = ref(StringUtils.class).staticInvoke("isEmpty"); isEmpty.arg(getAttribute); return isEmpty; } private Invocation generateGetAttributeConfigRef() { Invocation getTargetPropertyConfiguration = ExpressionFactory.invoke("getTargetPropertyConfiguration"); Invocation getAttributeAlias = getTargetPropertyConfiguration.invoke("getAttributeAlias"); getAttributeAlias.arg("config-ref"); return getAttributeAlias; } private Invocation generateAddPropertyValue(Variable element, Variable beanDefinitionBuilder, VariableElement variable) { Invocation getAttributeValue = ExpressionFactory.invoke("getAttributeValue"); getAttributeValue.arg(element); getAttributeValue.arg(ExpressionFactory.lit(variable.getSimpleName().toString())); Invocation addPropertyValue = beanDefinitionBuilder.invoke("addPropertyValue"); addPropertyValue.arg(ExpressionFactory.lit(variable.getSimpleName().toString())); addPropertyValue.arg(getAttributeValue); return addPropertyValue; } private Invocation generateAddPropertyRefValue(Variable element, Variable beanDefinitionBuilder, VariableElement variable) { Invocation getAttributeValue = ExpressionFactory.invoke("getAttributeValue"); getAttributeValue.arg(element); getAttributeValue.arg(ExpressionFactory.lit(variable.getSimpleName().toString() + "-ref")); Invocation addPropertyValue = beanDefinitionBuilder.invoke("addPropertyValue"); addPropertyValue.arg(ExpressionFactory.lit(variable.getSimpleName().toString())); addPropertyValue.arg(getAttributeValue); return addPropertyValue; } private Variable generateBeanAssembler(Method parseChild, Variable element, Variable beanDefinitionBuilder) { Variable assembler = parseChild.body().decl(ref(BeanAssembler.class), "assembler"); Invocation getBeanAssembler = ExpressionFactory.invoke("getBeanAssembler"); getBeanAssembler.arg(element); getBeanAssembler.arg(beanDefinitionBuilder); parseChild.body().assign(assembler, getBeanAssembler); return assembler; } private void generatePostProcessCall(Method parseChild, Variable element, Variable assembler) { Invocation postProcess = parseChild.body().invoke("postProcess"); postProcess.arg(ExpressionFactory.invoke("getParserContext")); postProcess.arg(assembler); postProcess.arg(element); } private class UpperBlockClosure { private Variable managedCollection; private Block notRefBlock; private UpperBlockClosure(Variable managedCollection, Block notRefBlock) { this.managedCollection = managedCollection; this.notRefBlock = notRefBlock; } public Variable getManagedCollection() { return managedCollection; } public void setManagedCollection(Variable managedCollection) { this.managedCollection = managedCollection; } public Block getNotRefBlock() { return notRefBlock; } public void setNotRefBlock(Block notRefBlock) { this.notRefBlock = notRefBlock; } } }