提交 aed15049 编写于 作者: sq3536's avatar sq3536

handlebars

上级 53acf7a5
......@@ -18,6 +18,7 @@
package cn.ibizlab.codegen;
import cn.ibizlab.codegen.config.GlobalSettings;
import cn.ibizlab.codegen.templating.MustacheEngineAdapter;
import cn.ibizlab.codegen.templating.TemplateDefinition;
import cn.ibizlab.codegen.templating.TemplatingEngineAdapter;
import cn.ibizlab.codegen.templating.mustache.*;
......@@ -110,18 +111,22 @@ public class CodegenConfig {
public CodegenConfig addLambda()
{
additionalProperties.put("lowercase", new LowercaseLambda().generator(this));
additionalProperties.put("uppercase", new UppercaseLambda());
additionalProperties.put("snakecase", new SnakecaseLambda());
additionalProperties.put("spinalcase", new SpinalcaseLambda());
additionalProperties.put("titlecase", new TitlecaseLambda());
additionalProperties.put("pluralize", new PluralizeLambda());
additionalProperties.put("camelcase", new CamelCaseLambda(true).generator(this));
additionalProperties.put("pascalcase", new CamelCaseLambda(false).generator(this));
additionalProperties.put("indented", new IndentedLambda());
additionalProperties.put("indented_8", new IndentedLambda(8, " "));
additionalProperties.put("indented_12", new IndentedLambda(12, " "));
additionalProperties.put("indented_16", new IndentedLambda(16, " "));
if(templatingEngine instanceof MustacheEngineAdapter)
{
additionalProperties.put("lowercase", new LowercaseLambda().generator(this));
additionalProperties.put("uppercase", new UppercaseLambda());
additionalProperties.put("snakecase", new SnakecaseLambda());
additionalProperties.put("spinalcase", new SpinalcaseLambda());
additionalProperties.put("titlecase", new TitlecaseLambda());
additionalProperties.put("pluralize", new PluralizeLambda());
additionalProperties.put("camelcase", new CamelCaseLambda(true).generator(this));
additionalProperties.put("pascalcase", new CamelCaseLambda(false).generator(this));
additionalProperties.put("indented", new IndentedLambda());
additionalProperties.put("indented_8", new IndentedLambda(8, " "));
additionalProperties.put("indented_12", new IndentedLambda(12, " "));
additionalProperties.put("indented_16", new IndentedLambda(16, " "));
}
return this;
}
......
......@@ -19,6 +19,7 @@ package cn.ibizlab.codegen.config;
import cn.ibizlab.codegen.CodegenConfig;
import cn.ibizlab.codegen.CodegenConstants;
import cn.ibizlab.codegen.templating.HandlebarsEngineAdapter;
import cn.ibizlab.codegen.templating.MustacheEngineAdapter;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
......@@ -242,7 +243,7 @@ public final class CodegenConfigurator {
TemplatingEngineAdapter templatingEngine = new MustacheEngineAdapter();
TemplatingEngineAdapter templatingEngine = new HandlebarsEngineAdapter();
config.setTemplatingEngine(templatingEngine);
if(this.additionalProperties!=null)
......
......@@ -2,7 +2,7 @@ package cn.ibizlab.codegen.model;
import org.springframework.util.StringUtils;
public class BaseModel {
public class BaseModel implements IModel {
protected String id;
......
......@@ -46,7 +46,7 @@ public class CliOption extends DataObj
this.set(templateFileType.name(),baseData);
this.set(templateFileType.value(),path);
if(!StringUtils.isEmpty(this.cliSubType))
this.set(templateFileType.value()+"#"+this.cliSubType,path);
this.set(templateFileType.value()+"__"+this.cliSubType,path);
return this;
}
......
package cn.ibizlab.codegen.model;
public interface IModel {
Object getOpt();
}
......@@ -37,7 +37,7 @@ public class LabelExt implements java.io.Serializable, Comparable<String>, CharS
}
public String toSpinalCase() {
return StringAdvUtils.dashize(label);
return StringAdvUtils.spinalcase(label);
}
public String toSnakeCase() {
......
/*
* Copyright 2019 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* 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
*
* https://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 cn.ibizlab.codegen.templating;
import java.util.Locale;
/**
* Provides abstractions around the template engine adapter interface, for reuse by implementers.
*/
public abstract class AbstractTemplatingEngineAdapter implements TemplatingEngineAdapter {
/**
* Gets all possible template paths for a given location.
*
* @param location The full location of the template.
*
* @return A new array of locations, modified according to the extensions or other adapter rules.
*/
protected String[] getModifiedFileLocation(String location) {
String[] extensions = getFileExtensions();
String[] result = new String[extensions.length+1];
result[0]=location;
for (int i = 0; i < extensions.length; i++) {
String extension = extensions[i];
result[i+1] = String.format(Locale.ROOT, "%s.%s", (location), extension);
}
return result;
}
/**
* Returns the path without an extension for an input location.
*
* @param location The location of the file, with original file extension intact.
*
* @return The full path, without extension (e.g. /path/to/file.txt => /path/to/file)
*/
private String getPathWithoutExtension(String location) {
if (location == null) return null;
int idx = location.lastIndexOf('.');
if (idx == -1) return location;
return location.substring(0, idx);
}
}
/*
* Copyright 2019 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* 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
*
* https://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 cn.ibizlab.codegen.templating;
import cn.ibizlab.codegen.templating.handlebars.BaseModelValueResolver;
import com.github.jknack.handlebars.Context;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Jackson2Helper;
import com.github.jknack.handlebars.Template;
import com.github.jknack.handlebars.context.FieldValueResolver;
import com.github.jknack.handlebars.context.JavaBeanValueResolver;
import com.github.jknack.handlebars.context.MapValueResolver;
import com.github.jknack.handlebars.context.MethodValueResolver;
import com.github.jknack.handlebars.helper.ConditionalHelpers;
import com.github.jknack.handlebars.helper.StringHelpers;
import com.github.jknack.handlebars.io.AbstractTemplateLoader;
import com.github.jknack.handlebars.io.StringTemplateSource;
import com.github.jknack.handlebars.io.TemplateLoader;
import com.github.jknack.handlebars.io.TemplateSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
public class HandlebarsEngineAdapter extends AbstractTemplatingEngineAdapter {
final Logger LOGGER = LoggerFactory.getLogger(HandlebarsEngineAdapter.class);
private final String[] extensions = {"handlebars", "hbs"};
// We use this as a simple lookup for valid file name extensions. This adapter will inspect .mustache (built-in) and infer the relevant handlebars filename
private final String[] canCompileFromExtensions = {".handlebars",".hbs",".mustache"};
private boolean infiniteLoops = false;
private boolean prettyPrint = false;
/**
* Provides an identifier used to load the adapter. This could be a name, uuid, or any other string.
*
* @return A string identifier.
*/
@Override
public String getIdentifier() {
return "handlebars";
}
public String compileTemplate(TemplatingExecutor executor,
Map<String, Object> bundle, String templateFile) throws IOException {
TemplateLoader loader = new AbstractTemplateLoader() {
@Override
public TemplateSource sourceAt(String location) {
return findTemplate(executor, location);
}
};
Context context = Context
.newBuilder(bundle)
.resolver(
MapValueResolver.INSTANCE,
// JavaBeanValueResolver.INSTANCE,
BaseModelValueResolver.INSTANCE,
FieldValueResolver.INSTANCE,
MethodValueResolver.INSTANCE)
.build();
Handlebars handlebars = new Handlebars(loader);
handlebars.registerHelperMissing((obj, options) -> {
LOGGER.warn(String.format(Locale.ROOT, "Unregistered helper name '%s', processing template:%n%s", options.helperName, options.fn.text()));
return "";
});
handlebars.registerHelper("json", Jackson2Helper.INSTANCE);
StringHelpers.register(handlebars);
handlebars.registerHelpers(ConditionalHelpers.class);
handlebars.registerHelpers(cn.ibizlab.codegen.templating.handlebars.StringHelpers.class);
handlebars.setInfiniteLoops(infiniteLoops);
handlebars.setPrettyPrint(prettyPrint);
Template tmpl = handlebars.compile(templateFile);
return tmpl.apply(context);
}
@Override
public String compilePath(TemplatingExecutor executor, Map<String, Object> bundle, String templateFile) throws IOException {
Context context = Context
.newBuilder(bundle)
.resolver(
MapValueResolver.INSTANCE,
JavaBeanValueResolver.INSTANCE,
FieldValueResolver.INSTANCE,
MethodValueResolver.INSTANCE)
.build();
Handlebars handlebars = new Handlebars();
handlebars.registerHelperMissing((obj, options) -> {
LOGGER.warn(String.format(Locale.ROOT, "Unregistered helper name '%s', processing template:%n%s", options.helperName, options.fn.text()));
return "";
});
handlebars.registerHelper("json", Jackson2Helper.INSTANCE);
StringHelpers.register(handlebars);
handlebars.registerHelpers(ConditionalHelpers.class);
handlebars.registerHelpers(cn.ibizlab.codegen.templating.handlebars.StringHelpers.class);
handlebars.setInfiniteLoops(infiniteLoops);
handlebars.setPrettyPrint(prettyPrint);
Template tmpl = handlebars.compileInline(templateFile);
return tmpl.apply(context);
}
@SuppressWarnings("java:S108")
public TemplateSource findTemplate(TemplatingExecutor generator, String templateFile) {
String[] possibilities = getModifiedFileLocation(templateFile);
for (String file : possibilities) {
try {
return new StringTemplateSource(file, generator.getFullTemplateContents(file));
} catch (Exception ignored) {
}
}
throw new TemplateNotFoundException(String.join(", ", possibilities));
}
@Override
public String[] getFileExtensions() {
return extensions;
}
/**
* Determine if the adapter handles compilation of the file
*
* @param filename The template filename
* @return True if the file should be compiled by this adapter, else false.
*/
@Override
public boolean handlesFile(String filename) {
// disallow any extension-only files like ".hbs" or ".mustache", and only consider a file compilable if it's handlebars or mustache (from which we later infer the handlebars filename)
return Arrays.stream(canCompileFromExtensions).anyMatch(suffix -> !suffix.equalsIgnoreCase(filename) && filename.endsWith(suffix));
}
/**
* Enable/disable infiniteLoops setting for the Handlebars engine. Enabling this allows for recursive partial inclusion.
*
* @param infiniteLoops Whether to enable (true) or disable (false)
* @return this object
*/
public HandlebarsEngineAdapter infiniteLoops(boolean infiniteLoops) {
this.infiniteLoops = infiniteLoops;
return this;
}
public void setPrettyPrint(boolean prettyPrint) {
this.prettyPrint = prettyPrint;
}
}
......@@ -28,7 +28,7 @@ import java.io.StringReader;
import java.util.Map;
public class MustacheEngineAdapter implements TemplatingEngineAdapter {
public class MustacheEngineAdapter extends AbstractTemplatingEngineAdapter {
private final Logger LOGGER = LoggerFactory.getLogger(TemplatingEngineAdapter.class);
......@@ -42,7 +42,13 @@ public class MustacheEngineAdapter implements TemplatingEngineAdapter {
return "mustache";
}
Mustache.Compiler compiler = Mustache.compiler().withCollector(new MustacheCollector());
@Override
public String[] getFileExtensions() {
return extensions;
}
private final String[] extensions = {"mustache"};
Mustache.Compiler compiler = Mustache.compiler();
/**
* Compiles a template into a string
......@@ -77,12 +83,17 @@ public class MustacheEngineAdapter implements TemplatingEngineAdapter {
@SuppressWarnings("java:S108") // catch-all is expected, and is later thrown
public Reader findTemplate(TemplatingExecutor generator, String templateName) {
try {
return new StringReader(generator.getFullTemplateContents(templateName));
} catch (Exception exception) {
LOGGER.error("Failed to read full template {}, {}", templateName, exception.getMessage());
String[] possibilities = getModifiedFileLocation(templateName);
for (String file : possibilities) {
try {
return new StringReader(generator.getFullTemplateContents(file));
} catch (Exception exception) {
LOGGER.error("Failed to read full template {}, {}", templateName, exception.getMessage());
}
}
throw new TemplateNotFoundException(templateName);
}
......
......@@ -55,7 +55,7 @@ public class TemplateDefinition {
Pattern p = Pattern.compile("\\{\\{([^}]*)\\}\\}");
Matcher m = p.matcher(fileName);
while (m.find()) {
String[] pairs=m.group(1).split("#");
String[] pairs=m.group(1).split("__");
if(type.name().equalsIgnoreCase(pairs[0])
||type.value().equalsIgnoreCase(pairs[0])) {
if(pairs.length>1&&(!StringUtils.isEmpty(pairs[1])))
......
......@@ -20,6 +20,7 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Map;
/**
......@@ -34,7 +35,24 @@ public interface TemplatingEngineAdapter {
*/
String getIdentifier();
/**
* During generation, if a supporting file has a file extension that is
* inside that array, then it is considered a templated supporting file
* and we use the templating engine adapter to generate it
*
* @return string array of the valid file extensions for this templating engine
*/
String[] getFileExtensions();
/**
* Determine if the adapter handles compilation of the file
* @param filename The template filename
*
* @return True if the file should be compiled by this adapter, else false.
*/
default boolean handlesFile(String filename) {
return filename != null && filename.length() > 0 && Arrays.stream(getFileExtensions()).anyMatch(i -> filename.endsWith("." + i));
}
/**
* Compiles a template into a string
......
/**
* Copyright (c) 2012-2015 Edgar Espina
* <p>
* This file is part of Handlebars.java.
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 cn.ibizlab.codegen.templating.handlebars;
import cn.ibizlab.codegen.model.BaseModel;
import cn.ibizlab.codegen.model.IModel;
import com.github.jknack.handlebars.ValueResolver;
import com.github.jknack.handlebars.context.MethodValueResolver;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static org.apache.commons.lang3.Validate.notNull;
/**
* A JavaBean method value resolver.
*
* @author edgar.espina
* @since 0.1.1
*/
public class BaseModelValueResolver implements ValueResolver {
/**
* A concurrent and thread-safe cache for {@link Member}.
*/
private final Map<Class<?>, Map<String, Method>> cache = new ConcurrentHashMap<>();
@Override
public final Object resolve(final Object context, final String name) {
Class<?> key = context.getClass();
Map<String, Method> mcache = cache(key);
Method member = mcache.get(name);
if (member == null) {
if(context instanceof IModel)
{
mcache = cache(((IModel) context).getOpt().getClass());
member = mcache.get(name);
if (member == null) {
return UNRESOLVED;
} else {
return invokeMember(member, ((IModel) context).getOpt());
}
}
return UNRESOLVED;
} else {
return invokeMember(member, context);
}
}
@Override
public Object resolve(final Object context) {
return UNRESOLVED;
}
/**
* Get or build a class member cache.
*
* @param clazz Owner/key.
* @return A class cache.
*/
private Map<String, Method> cache(final Class<?> clazz) {
Map<String, Method> mcache = this.cache.get(clazz);
if (mcache == null) {
mcache = new HashMap<>();
Set<Method> members = members(clazz);
for (Method m : members) {
// Mark as accessible.
if (m instanceof AccessibleObject) {
((AccessibleObject) m).setAccessible(true);
}
mcache.put(memberName(m), m);
}
this.cache.put(clazz, mcache);
}
return mcache;
}
/**
* True if the member is public.
*
* @param member The member object.
* @return True if the member is public.
*/
protected boolean isPublic(final Method member) {
return Modifier.isPublic(member.getModifiers());
}
/**
* True if the member is private.
*
* @param member The member object.
* @return True if the member is private.
*/
protected boolean isPrivate(final Method member) {
return Modifier.isPrivate(member.getModifiers());
}
/**
* True if the member is protected.
*
* @param member The member object.
* @return True if the member is protected.
*/
protected boolean isProtected(final Method member) {
return Modifier.isProtected(member.getModifiers());
}
/**
* True if the member is static.
*
* @param member The member object.
* @return True if the member is static.
*/
protected boolean isStatic(final Method member) {
return Modifier.isStatic(member.getModifiers());
}
@Override
public Set<Map.Entry<String, Object>> propertySet(final Object context) {
notNull(context, "The context is required.");
if (context instanceof Map) {
return Collections.emptySet();
} else if (context instanceof Collection) {
return Collections.emptySet();
}
Collection<Method> members = cache(context.getClass()).values();
Map<String, Object> propertySet = new LinkedHashMap<>();
for (Method member : members) {
String name = memberName(member);
propertySet.put(name, resolve(context, name));
}
return propertySet.entrySet();
}
/**
* Args for getters.
*/
private static final Object[] EMPTY_ARGS = new Object[0];
protected Object invokeMember(final Method member, final Object context) {
try {
return member.invoke(context, EMPTY_ARGS);
} catch (InvocationTargetException ex) {
Throwable cause = ex.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
}
throw new IllegalStateException("Execution of '" + member.getName() + "' failed", cause);
} catch (IllegalAccessException ex) {
throw new IllegalStateException(
"Could not access method: '" + member.getName() + "'", ex);
}
}
protected Set<Method> members(final Class<?> clazz) {
Set<Method> members = new LinkedHashSet<>();
members(clazz, members);
return members;
}
/**
* The 'is' prefix.
*/
private static final String IS_PREFIX = "is";
/**
* The 'get' prefix.
*/
private static final String GET_PREFIX = "get";
/**
* The default value resolver.
*/
public static final ValueResolver INSTANCE = new BaseModelValueResolver();
public boolean matches(final Method method, final String name) {
if (name.equals("length") && method.getName().equals("size")) {
boolean isCollection = isCollectionMethod(method);
if (isCollection) {
return true;
}
}
boolean isStatic = isStatic(method);
boolean isPublic = isPublic(method);
boolean isGet = method.getName().equals(javaBeanMethod(GET_PREFIX, name));
boolean isBoolGet = method.getName().equals(javaBeanMethod(IS_PREFIX, name));
int parameterCount = method.getParameterTypes().length;
return !isStatic && isPublic && parameterCount == 0 && (isGet || isBoolGet);
}
/**
* Convert the property's name to a JavaBean read method name.
*
* @param prefix The prefix: 'get' or 'is'.
* @param name The unqualified property name.
* @return The javaBean method name.
*/
private static String javaBeanMethod(final String prefix,
final String name) {
StringBuilder buffer = new StringBuilder(prefix);
buffer.append(name);
buffer.setCharAt(prefix.length(), Character.toUpperCase(name.charAt(0)));
return buffer.toString();
}
protected String memberName(final Method member) {
if (member.getName().equals("size")) {
boolean isCollection = isCollectionMethod(member);
if (isCollection) {
return "length";
}
}
String name = member.getName();
if (name.startsWith(GET_PREFIX)) {
name = name.substring(GET_PREFIX.length());
} else if (name.startsWith(IS_PREFIX)) {
name = name.substring(IS_PREFIX.length());
} else {
return name;
}
if (name.length() > 0) {
return Character.toLowerCase(name.charAt(0)) + name.substring(1);
}
return member.getName();
}
/**
* Collect all the method from the given class.
*
* @param clazz The base class.
* @param members The members result set.
*/
protected void members(final Class<?> clazz, final Set<Method> members) {
if (clazz != Object.class) {
// Keep backing up the inheritance hierarchy.
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (matches(method, memberName(method))) {
members.add(method);
}
}
if (clazz.getSuperclass() != null) {
members(clazz.getSuperclass(), members);
}
for (Class<?> superIfc : clazz.getInterfaces()) {
members(superIfc, members);
}
}
}
/**
* Check is method class implements Collection interface.
*
* @param method from class
* @return true/false
*/
private boolean isCollectionMethod(final Method method) {
for (Class clazz : method.getDeclaringClass().getInterfaces()) {
if (Collection.class.equals(clazz)) {
return true;
}
}
return false;
}
}
package cn.ibizlab.codegen.templating.handlebars;
import cn.ibizlab.codegen.utils.Inflector;
import cn.ibizlab.codegen.utils.StringAdvUtils;
import com.github.jknack.handlebars.Helper;
import com.github.jknack.handlebars.Options;
import com.github.jknack.handlebars.TagType;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.Locale;
public enum StringHelpers implements Helper<Object> {
/**
* Indicates the string starts with the defined value.
* For example:
*
* <pre>
* {{startsWith a b ["insensitive"]}}
* </pre>
*
* <pre>
* {{startsWith a text='b' [insensitive=true]}}
* </pre>
*
* Render 'yes' or 'no':
* <pre>
* {{#startsWith a b}}
* yes
* {{else}}
* no
* {{/startsWith}}
* </pre>
*
* Render 'true' or 'false':
* <pre>
* {{startsWith a b}}
* </pre>
*
* Render 'y' or 'n':
* <pre>
* {{startsWith a b yes='y' no='n'}}
* </pre>
*
* If value is "handlebars.java", the output will be "Handlebars.java".
*/
startsWith {
@Override
public Object apply(Object value, Options options) throws IOException {
String match = options.param(0, options.hash("text", ""));
if (match.length() < 1) {
return false;
}
boolean caseInsensitive = options.hash("insensitive", false);
boolean result = caseInsensitive ? value.toString().toLowerCase(Locale.ROOT).startsWith(match.toLowerCase(Locale.ROOT)) : value.toString().startsWith(match);
if (options.tagType == TagType.SECTION) {
return result ? options.fn() : options.inverse();
}
return result
? options.hash("yes", true)
: options.hash("no", false);
}
@Override
protected CharSequence safeApply(Object context, Options options) {
return null;
}
},
lowerCase {
@Override
protected CharSequence safeApply(final Object value, final Options options) {
return value.toString().toLowerCase();
}
},
upperCase {
@Override
protected CharSequence safeApply(final Object value, final Options options) {
return value.toString().toUpperCase();
}
},
pascalCase {
@Override
protected CharSequence safeApply(final Object value, final Options options) {
return StringAdvUtils.pascalcase(value.toString());
}
},
capFirst {
@Override
protected CharSequence safeApply(final Object value, final Options options) {
return StringAdvUtils.pascalcase(value.toString());
}
},
camelCase {
@Override
protected CharSequence safeApply(final Object value, final Options options) {
return StringAdvUtils.camelcase(value.toString());
}
},
spinalCase {
@Override
protected CharSequence safeApply(final Object value, final Options options) {
return StringAdvUtils.spinalcase(value.toString());
}
},
snakeCase {
@Override
protected CharSequence safeApply(final Object value, final Options options) {
return StringAdvUtils.snakecase(value.toString());
}
},
pluralize {
@Override
protected CharSequence safeApply(final Object value, final Options options) {
return Inflector.getInstance().pluralize(StringAdvUtils.camelcase(value.toString()));
}
};
@Override
public Object apply(final Object context, final Options options) throws IOException {
if (options.isFalsy(context)) {
Object param = options.param(0, null);
return param == null ? null : param.toString();
}
return safeApply(context, options);
}
/**
* Apply the helper to the context.
*
* @param context The context object (param=0).
* @param options The options object.
* @return A string result.
*/
protected abstract CharSequence safeApply(Object context, Options options);
}
......@@ -9,7 +9,7 @@
<name>{{projectDesc}}</name>
<description></description>
<packaging>pom</packaging>
{{>{{{{!}}projectName}}-util/pom.xml}}
<parent>
<groupId>{{packageName}}</groupId>
<artifactId>{{projectName}}-dependencies</artifactId>
......
......@@ -37,7 +37,7 @@ import com.baomidou.mybatisplus.core.toolkit.IdWorker;
@Accessors(chain = true)
@JsonIgnoreProperties(value = "handler")
@TableName(value = "{{entity.tableName}}", resultMap = "{{entity.codeName}}ResultMap")
@ApiModel("{{entity.logicName}}")
@ApiModel("{{entity.logicName}}{{entity.enableAPIStorage}}")
public class {{entity.codeName}} extends EntityMP implements Serializable
{
......
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册