/* * MIT License * * Copyright (c) 2014 Klemm Software Consulting, Mirko Klemm * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.kscs.util.plugins.xjc; import java.util.ArrayList; import java.util.Collection; import com.kscs.util.plugins.xjc.codemodel.NestedThisRef; import com.kscs.util.plugins.xjc.outline.DefinedInterfaceOutline; import com.kscs.util.plugins.xjc.outline.DefinedPropertyOutline; import com.kscs.util.plugins.xjc.outline.DefinedTypeOutline; import com.kscs.util.plugins.xjc.outline.TypeOutline; import com.sun.codemodel.JClassAlreadyExistsException; import com.sun.codemodel.JConditional; import com.sun.codemodel.JDefinedClass; import com.sun.codemodel.JExpr; import com.sun.codemodel.JFieldRef; import com.sun.codemodel.JFieldVar; import com.sun.codemodel.JMethod; import com.sun.codemodel.JMod; import com.sun.codemodel.JVar; /** * @author Mirko Klemm 2015-03-12 */ public class ModifierGenerator { public static final String MODIFIER_CACHE_FIELD_NAME = "__cachedModifier__"; public static final String SETTER_PREFIX = "set"; public static final String GETTER_PREFIX = "get"; private final DefinedTypeOutline classOutline; private final JDefinedClass modifierClass; private final boolean implement; public static void generateClass(final PluginContext pluginContext, final DefinedTypeOutline classOutline, final String modifierClassName, final String modifierInterfaceName, final Collection<TypeOutline> suerInterfaces, final String modifierMethodName) throws JClassAlreadyExistsException { new ModifierGenerator(pluginContext, classOutline, modifierClassName, modifierInterfaceName, suerInterfaces, modifierMethodName, true).generatePropertyAccessors(); } public static void generateClass(final PluginContext pluginContext, final DefinedTypeOutline classOutline, final String modifierClassName, final String modifierMethodName) throws JClassAlreadyExistsException { new ModifierGenerator(pluginContext, classOutline, modifierClassName, null, null, modifierMethodName, true).generatePropertyAccessors(); } public static void generateInterface(final PluginContext pluginContext, final DefinedTypeOutline classOutline, final String modifierInterfaceName, final Collection<TypeOutline> interfaces, final String modifierMethodName) throws JClassAlreadyExistsException { new ModifierGenerator(pluginContext, classOutline, modifierInterfaceName, modifierInterfaceName, interfaces, modifierMethodName, false).generatePropertyAccessors(); } private ModifierGenerator(final PluginContext pluginContext, final DefinedTypeOutline classOutline, final String modifierClassName, final String modifierInterfaceName, final Collection<TypeOutline> interfaces, final String modifierMethodName, final boolean implement) throws JClassAlreadyExistsException { this.classOutline = classOutline; final JDefinedClass definedClass = classOutline.getImplClass(); this.implement = implement; this.modifierClass = definedClass._class(JMod.PUBLIC, modifierClassName, classOutline.getImplClass().getClassType()); if(interfaces != null) { for (final TypeOutline interfaceOutline : interfaces) { this.modifierClass._implements( pluginContext.ref(interfaceOutline.getImplClass(), modifierInterfaceName, true)); } } final JFieldRef cachedModifierField; if(!"java.lang.Object".equals(definedClass._extends().fullName())) { this.modifierClass._extends(pluginContext.ref(definedClass._extends(), modifierClassName, false)); cachedModifierField = JExpr.refthis(ModifierGenerator.MODIFIER_CACHE_FIELD_NAME); } else { if(implement) { cachedModifierField = JExpr._this().ref(definedClass.field(JMod.PROTECTED | JMod.TRANSIENT, this.modifierClass, ModifierGenerator.MODIFIER_CACHE_FIELD_NAME)); } else { cachedModifierField = null; } } final JDefinedClass typeDefinition = classOutline.isInterface() && ((DefinedInterfaceOutline)classOutline).getSupportInterface() != null ? ((DefinedInterfaceOutline)classOutline).getSupportInterface() : definedClass; final JMethod modifierMethod = typeDefinition.method(JMod.PUBLIC, this.modifierClass, modifierMethodName); if(this.implement) { final JConditional ifCacheNull = modifierMethod.body()._if(JExpr._null().eq(cachedModifierField)); ifCacheNull._then().assign(cachedModifierField, JExpr._new(this.modifierClass)); modifierMethod.body()._return(JExpr.cast(this.modifierClass, cachedModifierField)); } } private void generatePropertyAccessors() { for(final DefinedPropertyOutline fieldOutline:this.classOutline.getDeclaredFields()) { generatePropertyAccessor(fieldOutline); } } private void generatePropertyAccessor(final DefinedPropertyOutline fieldOutline) { if(fieldOutline.isCollection() && !fieldOutline.isArray()) { generateCollectionAccessor(fieldOutline); } else { generateSingularPropertyAccessor(fieldOutline); } } private void generateSingularPropertyAccessor(final DefinedPropertyOutline fieldOutline) { final JFieldVar fieldVar = fieldOutline.getFieldVar(); if(fieldVar != null) { final JMethod modifier = this.modifierClass.method(JMod.PUBLIC, this.modifierClass.owner().VOID, ModifierGenerator.SETTER_PREFIX + fieldOutline.getBaseName()); final JVar parameter = modifier.param(JMod.FINAL, fieldVar.type(), fieldOutline.getFieldName()); if(this.implement) { modifier.body().add(new NestedThisRef(this.classOutline.getImplClass()).invoke(modifier.name()).arg(parameter)); } } } private void generateCollectionAccessor(final DefinedPropertyOutline fieldOutline) { final JFieldVar fieldVar = fieldOutline.getFieldVar(); if(fieldVar != null) { final JMethod modifier = this.modifierClass.method(JMod.PUBLIC, fieldVar.type(), ModifierGenerator.GETTER_PREFIX + fieldOutline.getBaseName()); if(this.implement) { final JFieldRef fieldRef = new NestedThisRef(this.classOutline.getImplClass()).ref(fieldVar); final JConditional ifNull = modifier.body()._if(fieldRef.eq(JExpr._null())); ifNull._then().assign(fieldRef, JExpr._new(this.classOutline.getImplClass().owner().ref(ArrayList.class).narrow(fieldOutline.getElementType()))); modifier.body()._return(fieldRef); } } } }