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

init

上级 cb92a3f6
*volumes
*target
.settings
*node_modules
*bin
*.project
*.classpath
*.factorypath
.history
.vscode
.idea
**.iml
*.jar
*.log
.DS_Store
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ibizlab-generator-project</artifactId>
<groupId>com.ibizlab</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ibizlab-generator-cli</artifactId>
<build>
<finalName>ibizlab-generator-cli</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<configuration>
<configLocation>${project.parent.basedir}${file.separator}google_checkstyle.xml</configLocation>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
<configuration>
<archive>
<manifest>
<mainClass>com.ibizlab.codegen.IbizLabGenerator</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>process-resources</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>false</minimizeJar>
<createDependencyReducedPom>true</createDependencyReducedPom>
<dependencyReducedPomLocation>
${java.io.tmpdir}/dependency-reduced-pom.xml
</dependencyReducedPomLocation>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.ibizlab</groupId>
<artifactId>ibizlab-generator</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--https://github.com/airlift/airline-->
<dependency>
<groupId>io.airlift</groupId>
<artifactId>airline</artifactId>
<version>0.8</version>
</dependency>
<dependency>
<groupId>com.googlecode.lambdaj</groupId>
<artifactId>lambdaj</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>janino</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.ibizlab.codegen;
public class Constants {
private Constants(){ }
public static final String CLI_NAME = "ibizlab-generator-cli";
public static final String GIT_REPO = "https://github.com/ibiz4j/ibizlab-generator";
public static final String SITE = "https://www.ibizlab.cn/";
}
\ No newline at end of file
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen;
import io.airlift.airline.Cli;
import io.airlift.airline.ParseArgumentsUnexpectedException;
import io.airlift.airline.ParseOptionMissingException;
import io.airlift.airline.ParseOptionMissingValueException;
import com.ibizlab.codegen.cmd.*;
import java.util.Locale;
import static com.ibizlab.codegen.Constants.CLI_NAME;
/**
* User: lanwen Date: 24.03.15 Time: 17:56
* <p>
* Command line interface for OpenAPI Generator use `openapi-generator-cli.jar help` for more info
*/
public class IbizLabGenerator {
public static void main(String[] args) {
BuildInfo buildInfo = new BuildInfo();
Cli.CliBuilder<IbizLabGeneratorCommand> builder =
Cli.<IbizLabGeneratorCommand>builder(CLI_NAME)
.withDescription(
String.format(
Locale.ROOT,
"ibizLab Generator CLI %s (%s).",
buildInfo.getVersion(),
buildInfo.getSha()))
.withDefaultCommand(HelpCommand.class)
.withCommands(
Generate.class,
HelpCommand.class,
Version.class,
CompletionCommand.class
);
try {
builder.build().parse(args).run();
// If CLI runs without a command, consider this an error. This exists after initial parse/run
// so we can present the configured "default command".
// We can check against empty args because unrecognized arguments/commands result in an exception.
// This is useful to exit with status 1, for example, so that misconfigured scripts fail fast.
// We don't want the default command to exit internally with status 1 because when the default command is something like "list",
// it would prevent scripting using the command directly. Example:
// java -jar cli.jar list --short | tr ',' '\n' | xargs -I{} echo "Doing something with {}"
if (args.length == 0) {
System.exit(1);
}
} catch (ParseArgumentsUnexpectedException e) {
System.err.printf(Locale.ROOT, "[error] %s%n%nSee '%s help' for usage.%n", e.getMessage(), CLI_NAME);
System.exit(1);
} catch (ParseOptionMissingException | ParseOptionMissingValueException e) {
System.err.printf(Locale.ROOT, "[error] %s%n", e.getMessage());
System.exit(1);
}
}
}
package com.ibizlab.codegen.cmd;
import java.io.IOException;
import java.io.InputStream;
import java.time.DateTimeException;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Locale;
import java.util.Properties;
import static com.ibizlab.codegen.Constants.CLI_NAME;
import static com.ibizlab.codegen.Constants.GIT_REPO;
import static com.ibizlab.codegen.Constants.SITE;
/**
* Presents build-time information
*/
@SuppressWarnings({"java:S108"})
public class BuildInfo {
private static final String VERSION_PLACEHOLDER = "${project.version}";
private static final String UNSET = "unset";
private static final String UNKNOWN = "unknown";
private static final Properties properties = new Properties();
static {
try (InputStream is = BuildInfo.class.getResourceAsStream("/version.properties")) {
if (is != null) {
Properties versionProps = new Properties();
versionProps.load(is);
properties.putAll(versionProps);
}
} catch (IOException ignored) {
}
try (InputStream is = BuildInfo.class.getResourceAsStream("/openapi-generator-git.properties")) {
if (is != null) {
Properties gitProps = new Properties();
gitProps.load(is);
properties.putAll(gitProps);
}
} catch (IOException ignored) {
}
}
/**
* Gets the version of the toolset.
*
* @return A semver string
*/
public String getVersion() {
String version = (String) properties.getOrDefault("version", UNKNOWN);
if (VERSION_PLACEHOLDER.equals(version)) {
return UNSET;
} else {
return version;
}
}
/**
* Gets the git commit SHA1 hash. Useful for differentiating between SNAPSHOT builds.
*
* @return A short git SHA
*/
public String getSha() {
return (String) properties.getOrDefault("git.commit.id.abbrev", UNKNOWN);
}
/**
* Gets the time when this tool was built.
*
* @return The time as {@link OffsetDateTime}, or {@link OffsetDateTime#MIN} if metadata cannot be parsed.
*/
public OffsetDateTime getBuildTime() {
try {
String time = (String) properties.getOrDefault("git.build.time", "");
return OffsetDateTime.parse(time, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ", Locale.ROOT));
} catch (DateTimeParseException e) {
return OffsetDateTime.MIN;
}
}
/**
* Gets the full version display text, as one would expect from a '--version' CLI option
*
* @return Human-readable version display information
*/
public String versionDisplayText() {
StringBuilder sb = new StringBuilder(CLI_NAME);
sb.append(" ").append(this.getVersion()).append(System.lineSeparator());
sb.append(" commit : ").append(this.getSha()).append(System.lineSeparator());
sb.append(" built : ");
try {
sb.append(this.getBuildTime().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
} catch (DateTimeException e) {
sb.append(UNKNOWN);
}
sb.append(System.lineSeparator());
sb.append(" source : ").append(GIT_REPO).append(System.lineSeparator());
sb.append(" docs : ").append(SITE).append(System.lineSeparator());
return sb.toString();
}
}
/*
* Copyright (C) 2010 the original author or authors.
* Copyright 2018 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.
*/
/*
* NOTICE: File originally taken from:
* https://github.com/airlift/airline/blob/fc7a55e34b6361cb97235de5a1b21cba9b508f4b/src/main/java/io/airlift/airline/SuggestCommand.java#L1
* Modifications have been made to fit the needs of OpenAPI Tools CLI.
*/
package com.ibizlab.codegen.cmd;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import io.airlift.airline.*;
import io.airlift.airline.model.*;
import javax.inject.Inject;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import static com.google.common.collect.Lists.newArrayList;
import static io.airlift.airline.ParserUtil.createInstance;
@SuppressWarnings({"java:S106"})
@Command(name = "completion", description = "Complete commands (for using in tooling such as Bash Completions).", hidden = true)
public class CompletionCommand extends IbizLabGeneratorCommand
implements Runnable, Callable<Void> {
private static final Map<Context, Class<? extends Suggester>> BUILTIN_SUGGESTERS = ImmutableMap.<Context, Class<? extends Suggester>>builder()
.put(Context.GLOBAL, GlobalSuggester.class)
.put(Context.GROUP, GroupSuggester.class)
.put(Context.COMMAND, CommandSuggester.class)
.build();
@Inject
public GlobalMetadata metadata;
@Arguments
public List<String> arguments = newArrayList();
@Override
public Void call() {
run();
return null;
}
@VisibleForTesting
public Iterable<String> generateSuggestions() {
Parser parser = new Parser();
ParseState state = parser.parse(metadata, arguments);
Class<? extends Suggester> suggesterClass = BUILTIN_SUGGESTERS.get(state.getLocation());
if (suggesterClass != null) {
SuggesterMetadata suggesterMetadata = MetadataLoader.loadSuggester(suggesterClass);
if (suggesterMetadata != null) {
ImmutableMap.Builder<Class<?>, Object> bindings = ImmutableMap.<Class<?>, Object>builder()
.put(GlobalMetadata.class, metadata);
if (state.getGroup() != null) {
bindings.put(CommandGroupMetadata.class, state.getGroup());
}
if (state.getCommand() != null) {
bindings.put(CommandMetadata.class, state.getCommand());
}
Suggester suggester = createInstance(suggesterMetadata.getSuggesterClass(),
ImmutableList.<OptionMetadata>of(),
null,
null,
null,
suggesterMetadata.getMetadataInjections(),
bindings.build(),
new DefaultCommandFactory<Suggester>());
return suggester.suggest();
}
}
return ImmutableList.of();
}
@Override
void execute() {
System.out.println(Joiner.on("\n").join(generateSuggestions()));
}
}
\ No newline at end of file
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.cmd;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.spi.FilterAttachable;
import com.ibizlab.codegen.*;
import com.ibizlab.codegen.config.CodegenConfigurator;
import com.ibizlab.codegen.config.CodegenConfiguratorUtils;
import io.airlift.airline.Command;
import io.airlift.airline.Option;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import static com.ibizlab.codegen.config.CodegenConfiguratorUtils.applyAdditionalPropertiesKvpList;
import static com.ibizlab.codegen.config.CodegenConfiguratorUtils.applyGlobalPropertiesKvpList;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
@SuppressWarnings({"java:S106"})
@Command(name = "generate", description = "Generate code with the specified generator.")
public class Generate extends IbizLabGeneratorCommand {
CodegenConfigurator configurator;
Generator generator;
@Option(name = {"-o", "--output"}, title = "output directory",
description = "where to write the generated files (current dir by default)")
private String output = "";
@Option(name = {"-i", "--input-spec"}, title = "spec file",
description = "location of the OpenAPI spec, as URL or file (required if not loaded via config using -c)")
private String spec;
@Option(name = {"-t", "--template-dir"}, title = "template directory",
description = "folder containing the template files")
private String templateDir;
@Option(
name = {"-a", "--auth"},
title = "authorization",
description = "adds authorization headers when fetching the OpenAPI definitions remotely. "
+ "Pass in a URL-encoded string of name:header with a comma separating multiple values")
private String auth;
@Option(
name = {"--global-property"},
title = "global properties",
description = "sets specified global properties (previously called 'system properties') in "
+ "the format of name=value,name=value (or multiple options, each with name=value)")
private List<String> globalProperties = new ArrayList<>();
@Option(
name = {"-c", "--config"},
title = "configuration file",
description = "Path to configuration file. It can be JSON or YAML. "
+ "If file is JSON, the content should have the format {\"optionKey\":\"optionValue\", \"optionKey1\":\"optionValue1\"...}. "
+ "If file is YAML, the content should have the format optionKey: optionValue. "
+ "Supported options can be different for each language. Run config-help -g {generator name} command for language-specific config options.")
private String configFile;
@Option(name = {"-n","--project-name","--system-name"}, title = "package name",
description = CodegenConstants.PROJECT_NAME)
private String name;
@Option(name = {"--package-name"}, title = "package name",
description = CodegenConstants.PACKAGE_NAME_DESC)
private String packageName;
@Option(
name = {"-p", "--additional-properties"},
title = "additional properties",
description = "sets additional properties that can be referenced by the mustache templates in the format of name=value,name=value."
+ " You can also have multiple occurrences of this option.")
private List<String> additionalProperties = new ArrayList<>();
@Option(name = {"--git-host"}, title = "git host",
description = CodegenConstants.GIT_HOST_DESC)
private String gitHost;
@Option(name = {"--git-user-id"}, title = "git user id",
description = CodegenConstants.GIT_USER_ID_DESC)
private String gitUserId;
@Option(name = {"--git-repo-id"}, title = "git repo id",
description = CodegenConstants.GIT_REPO_ID_DESC)
private String gitRepoId;
@Option(name = {"--release-note"}, title = "release note",
description = CodegenConstants.RELEASE_NOTE_DESC)
private String releaseNote;
@Option(name = {"--http-user-agent"}, title = "http user agent",
description = CodegenConstants.HTTP_USER_AGENT_DESC)
private String httpUserAgent;
@Override
public void execute() {
// this initial check allows for field-level package private injection (for unit testing)
if (configurator == null) {
if (configFile != null && configFile.length() > 0) {
// attempt to load from configFile
configurator = CodegenConfigurator.fromFile(configFile);
} else if (StringUtils.isEmpty(spec)) {
// if user doesn't pass configFile and does not pass spec, we can fail immediately because one of these two is required to run.
System.err.println("[error] Required option '-i' is missing");
System.exit(1);
}
// if a config file wasn't specified, or we were unable to read it
if (configurator == null) {
// create a fresh configurator
configurator = new CodegenConfigurator();
}
}
if (isNotEmpty(spec)) {
if (!spec.matches("^http(s)?://.*") && !new File(spec).exists()) {
System.err.println("[error] The spec file is not found: " + spec);
System.err.println("[error] Check the path of the OpenAPI spec and try again.");
System.exit(1);
}
configurator.setInputSpec(spec);
}
if (isNotEmpty(output)) {
configurator.setOutputDir(output);
}
if (isNotEmpty(auth)) {
configurator.setAuth(auth);
}
if (isNotEmpty(templateDir)) {
configurator.setTemplateDir(templateDir);
}
if (isNotEmpty(packageName)) {
configurator.setPackageName(packageName);
}
if (isNotEmpty(name)) {
configurator.setProjectName(name);
}
if (isNotEmpty(gitHost)) {
configurator.setGitHost(gitHost);
}
if (isNotEmpty(gitUserId)) {
configurator.setGitUserId(gitUserId);
}
if (isNotEmpty(gitRepoId)) {
configurator.setGitRepoId(gitRepoId);
}
if (isNotEmpty(releaseNote)) {
configurator.setReleaseNote(releaseNote);
}
if (isNotEmpty(httpUserAgent)) {
configurator.setHttpUserAgent(httpUserAgent);
}
if (globalProperties != null && !globalProperties.isEmpty()) {
applyGlobalPropertiesKvpList(globalProperties, configurator);
}
applyAdditionalPropertiesKvpList(additionalProperties, configurator);
try {
final ClientOptInput clientOptInput = configurator.toClientOptInput();
// this null check allows us to inject for unit testing.
if (generator == null) {
generator = new DefaultGenerator(false);
}
generator.opts(clientOptInput);
generator.generate();
} catch (GeneratorNotFoundException e) {
System.err.println(e.getMessage());
System.err.println("[error] Check the spelling of the generator's name and try again.");
System.exit(1);
}
}
}
package com.ibizlab.codegen.cmd;
import io.airlift.airline.Option;
import static io.airlift.airline.OptionType.GLOBAL;
public class GlobalOptions {
@Option(type = GLOBAL, name = "--version", description = "Display full version output", hidden = true)
public boolean version;
@Option(type = GLOBAL, name = "--help", description = "Display help about the tool", hidden = true)
public boolean help;
}
package com.ibizlab.codegen.cmd;
import io.airlift.airline.Command;
import io.airlift.airline.Help;
import javax.inject.Inject;
@Command(name = "help", description = "Display help information about openapi-generator")
public class HelpCommand extends IbizLabGeneratorCommand {
@Inject
public Help help;
@Override
public void execute() {
help.call();
}
}
package com.ibizlab.codegen.cmd;
import io.airlift.airline.Help;
import io.airlift.airline.model.GlobalMetadata;
import javax.inject.Inject;
@SuppressWarnings({"java:S106"})
public abstract class IbizLabGeneratorCommand implements Runnable {
@Inject
public GlobalOptions globalOptions = new GlobalOptions();
@Inject
public GlobalMetadata global;
protected BuildInfo buildInfo = new BuildInfo();
@Override
public void run() {
if (globalOptions.version) {
System.out.println(buildInfo.versionDisplayText());
return;
}
if (globalOptions.help) {
Help help = new Help();
help.global = global;
help.call();
return;
}
execute();
}
/**
* Logic to be executed by implementing commands
*/
abstract void execute();
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.cmd;
import io.airlift.airline.Command;
import io.airlift.airline.Option;
@SuppressWarnings({"unused", "java:S106"})
@Command(name = "version", description = "Show version information used in tooling")
public class Version extends IbizLabGeneratorCommand {
@Option(name = {"--sha"}, description = "Git commit SHA version")
private Boolean sha;
@Option(name = {"--full"}, description = "Full version details")
private Boolean full;
@Override
public void execute() {
String version;
if (Boolean.TRUE.equals(full)) {
version = buildInfo.versionDisplayText();
} else if (Boolean.TRUE.equals(sha)) {
version = buildInfo.getSha();
} else {
version = buildInfo.getVersion();
}
System.out.println(version);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ibizlab-generator-project</artifactId>
<groupId>com.ibizlab</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.ibizlab</groupId>
<artifactId>ibizlab-generator-core</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-guava</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.github.joschi.jackson</groupId>
<artifactId>jackson-datatype-threetenbp</artifactId>
<version>${jackson-threetenbp.version}</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-core</artifactId>
<version>${swagger-core.version}</version>
</dependency>
<dependency>
<groupId>${swagger-parser-groupid.version}</groupId>
<artifactId>swagger-parser</artifactId>
<version>${swagger-parser.version}</version>
</dependency>
<dependency>
<groupId>com.samskivert</groupId>
<artifactId>jmustache</artifactId>
<version>${jmustache.version}</version>
</dependency>
<dependency>
<groupId>com.github.jknack</groupId>
<artifactId>handlebars</artifactId>
<version>${handlebars-java.version}</version>
</dependency>
<dependency>
<groupId>com.github.jknack</groupId>
<artifactId>handlebars-jackson2</artifactId>
<version>${handlebars-java.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-ext</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang.version}</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>${commons-cli.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>com.github.spullara.mustache.java</groupId>
<artifactId>compiler</artifactId>
<version>0.9.10</version>
</dependency>
<dependency>
<groupId>com.atlassian.commonmark</groupId>
<artifactId>commonmark</artifactId>
<version>0.11.0</version>
</dependency>
<dependency>
<groupId>com.github.mifmif</groupId>
<artifactId>generex</artifactId>
<version>${generex.version}</version>
</dependency>
<dependency>
<groupId>com.github.curious-odd-man</groupId>
<artifactId>rgxgen</artifactId>
<version>${rxgen.version}</version>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>net.ibizsys.model</groupId>
<artifactId>ibizlab-model</artifactId>
<version>1.2.9</version>
<exclusions>
<exclusion>
<artifactId>slf4j-simple</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.ibizlab.codegen.api;
import java.util.Locale;
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];
for (int i = 0; i < extensions.length; i++) {
String extension = extensions[i];
result[i] = String.format(Locale.ROOT, "%s.%s", getPathWithoutExtension(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);
}
}
package com.ibizlab.codegen.api;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.util.Objects;
import java.util.StringJoiner;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
public class TemplateDefinition {
private String templateFile;
private String folder;
private String destinationFilename;
protected TemplateFileType templateType;
public TemplateDefinition(String templateFile, String folder, String destinationFilename) {
if (templateFile == null) throw new IllegalArgumentException("templateFile may not be null.");
if (folder == null) throw new IllegalArgumentException("folder may not be null.");
if (destinationFilename == null) throw new IllegalArgumentException("destinationFilename may not be null.");
this.templateFile = templateFile;
this.folder = folder;
this.destinationFilename = destinationFilename;
this.templateType = TemplateFileType.SupportingFiles;
}
}
package com.ibizlab.codegen.api;
import java.util.StringJoiner;
public enum TemplateFileType {
API(Constants.APIS),
Model(Constants.MODELS),
APIDocs(Constants.API_DOCS),
ModelDocs(Constants.MODEL_DOCS),
APITests(Constants.API_TESTS),
ModelTests(Constants.MODEL_TESTS),
SupportingFiles(Constants.SUPPORTING_FILES);
private final String templateType;
TemplateFileType(String templateType) { this.templateType = templateType; }
/**
* Returns the value for this template file type
*
* @return The template type of this enum.
*/
public String value() { return this.templateType; }
/** {@inheritDoc} */
@Override
public String toString() {
return new StringJoiner(", ", TemplateFileType.class.getSimpleName() + "[", "]")
.add("templateType='" + templateType + "'")
.toString();
}
/**
* Obtains the {@link TemplateFileType} for an input string.
*
* @param templateType a {@link String} object.
* @return a {@link TemplateFileType} object.
*/
public static TemplateFileType forTemplateType(String templateType) {
for (TemplateFileType value : values()) {
if (value.templateType.equals(templateType)) {
return value;
}
}
throw new IllegalArgumentException("templateType not found in the available values.");
}
public static class Constants {
public static final String APIS = "apis";
public static final String MODELS = "models";
public static final String SUPPORTING_FILES = "supportingFiles";
public static final String MODEL_TESTS = "modelTests";
public static final String MODEL_DOCS = "modelDocs";
public static final String API_TESTS = "apiTests";
public static final String API_DOCS = "apiDocs";
}
}
package com.ibizlab.codegen.api;
/**
* Provides means for searching for "actual" template location based on relative template file.
*/
public interface TemplatePathLocator {
/**
* Get the full path to a relative template file.
*
* @param relativeTemplateFile Template file
* @return String Full template file path
*/
String getFullTemplatePath(String relativeTemplateFile);
}
package com.ibizlab.codegen.api;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Map;
/**
* Interface for abstractions around writing templated data to a file.
*/
public interface TemplateProcessor {
/**
* Writes data to a compiled template
*
* @param data Input data
* @param template Input template location
* @param target The targeted file output location
*
* @return The actual file
* @throws IOException If file cannot be written.
*/
File write(Map<String, Object> data, String template, File target) throws IOException;
/**
* Write bytes to a file
*
* @param filename The name of file to write
* @param contents The contents bytes. Typically this is a UTF-8 formatted string.
* @return File representing the written file.
* @throws IOException If file cannot be written.
*/
File writeToFile(String filename, byte[] contents) throws IOException;
/**
* Allow a caller to mark a path as ignored with accompanying reason
*
* @param path The ignored path
* @param context The reason for ignoring this path
*/
void ignore(Path path, String context);
/**
* Allow a caller to mark a path as skipped with accompanying reason
*
* @param path The skipped path
* @param context The reason for skipping this path
*/
void skip(Path path, String context);
/**
* Allow a caller to mark a path having errored during processing with accompanying reason
*
* @param path The path which has caused an error
* @param context The reason for the error
*/
default void error(Path path, String context) { }
}
/*
* 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 com.ibizlab.codegen.api;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
/**
* Each templating engine is called by an Adapter, selected at runtime
*/
public interface TemplatingEngineAdapter {
/**
* Provides an identifier used to load the adapter. This could be a name, uuid, or any other string.
*
* @return A string identifier.
*/
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
*
* @param executor From where we can fetch the templates content (e.g. an instance of DefaultGenerator)
* @param bundle The map of values to pass to the template
* @param templateFile The name of the template (e.g. model.mustache )
* @return the processed template result
* @throws IOException an error occurred in the template processing
*/
String compileTemplate(TemplatingExecutor executor, Map<String, Object> bundle,
String templateFile) throws IOException;
/**
* Determines whether the template file with supported extensions exists. This may be on the filesystem,
* external filesystem, or classpath (implementation is up to TemplatingGenerator).
*
* @param generator The generator holding details about file resolution
* @param templateFile The original target filename
* @return True if the template is available in the template search path, false if it can not be found
*/
@SuppressWarnings({"java:S2093"}) // ignore java:S2093 because we have double-assignment to the closeable
default boolean templateExists(TemplatingExecutor generator, String templateFile) {
return Arrays.stream(getFileExtensions()).anyMatch(ext -> {
int idx = templateFile.lastIndexOf('.');
String baseName;
if (idx > 0 && idx < templateFile.length() - 1) {
baseName = templateFile.substring(0, idx);
} else {
baseName = templateFile;
}
Path path = generator.getFullTemplatePath(String.format(Locale.ROOT, "%s.%s", baseName, ext));
InputStream is = null;
try {
String resourcePath = System.getProperty("os.name").startsWith("Windows") ?
path.toString().replace("\\", "/") :
path.toString();
is = this.getClass().getClassLoader().getResourceAsStream(resourcePath);
if (is == null) {
is = new FileInputStream(path.toFile());
}
return is.available() > 0;
} catch (IOException e) {
// ignore
} finally {
try {
if (is != null) is.close();
} catch (IOException e) {
// ignore
}
}
return false;
});
}
}
package com.ibizlab.codegen.api;
import java.nio.file.Path;
/**
* interface to the full template content
* implementers might take into account the -t cli option,
* look in the resources for a generator specific template, etc
*/
public interface TemplatingExecutor {
/**
* returns the template content by name
*
* @param name the template name (e.g. model.mustache)
* @return the contents of that template
*/
String getFullTemplateContents(String name);
/**
* Returns the path of a template, allowing access to the template where consuming literal contents aren't desirable or possible.
*
* @param name the template name (e.g. model.mustache)
* @return The {@link Path} to the template
*/
Path getFullTemplatePath(String name);
}
\ No newline at end of file
/*
* 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 com.ibizlab.codegen.config;
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
public class Context<TSpecDocument> {
private TSpecDocument specDocument;
private GeneratorSettings generatorSettings;
public static void main(String[] args) throws IOException {
HashMap<String, Object> scopes = new HashMap<String, Object>();
scopes.put("name", "Mustache");
GeneratorSettings generatorSettings=new GeneratorSettings().setGitHost("host");
generatorSettings.getAdditionalProperties().put("sub",new GeneratorSettings().setGitHost("son"));
scopes.put("feature",generatorSettings );
List<String> list=new ArrayList<>();
list.add("a");
list.add("b");
scopes.put("list",list);
Writer writer = new OutputStreamWriter(System.out);
MustacheFactory mf = new DefaultMustacheFactory();
Mustache mustache = mf.compile(new StringReader("{{name}}, {{#list}}{{.}}{{/list}}!"), "example");
mustache.execute(writer, scopes);
writer.flush();
}
}
package com.ibizlab.codegen.config;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.*;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
public class GeneratorSettings implements Serializable {
private static final Logger LOGGER = LoggerFactory.getLogger(GeneratorSettings.class);
private static final String DEFAULT_GIT_HOST = "github.com";
private static final String DEFAULT_GIT_USER_ID = "GIT_USER_ID";
private static final String DEFAULT_GIT_REPO_ID = "GIT_REPO_ID";
private static final String DEFAULT_RELEASE_NOTE = "Minor update";
private String projectName;
private String packageName;
private Map<String, Object> additionalProperties = new LinkedHashMap<>();
private String gitHost;
private String gitUserId;
private String gitRepoId;
private String releaseNote;
private String httpUserAgent;
private Map<String, String> typeMappings;
public String getHost()
{
return gitHost+"abc";
}
private GeneratorSettings(Builder builder) {
projectName = builder.projectName;
packageName = builder.packageName;
typeMappings = Collections.unmodifiableMap(builder.typeMappings);
gitHost = builder.gitHost;
gitUserId = builder.gitUserId;
gitRepoId = builder.gitRepoId;
releaseNote = builder.releaseNote;
httpUserAgent = builder.httpUserAgent;
Map<String, Object> additional = new HashMap<>(builder.additionalProperties);
additionalProperties = Collections.unmodifiableMap(additional);
}
public static Builder newBuilder(GeneratorSettings copy) {
Builder builder = new Builder();
builder.projectName = copy.projectName;
builder.packageName = copy.packageName;
builder.typeMappings = Collections.unmodifiableMap(copy.typeMappings);
builder.gitHost = copy.gitHost;
builder.gitUserId = copy.gitUserId;
builder.gitRepoId = copy.gitRepoId;
builder.releaseNote = copy.releaseNote;
builder.httpUserAgent = copy.httpUserAgent;
Map<String, Object> additional = new HashMap<>(copy.additionalProperties);
builder.additionalProperties = Collections.unmodifiableMap(additional);
return builder;
}
public static final class Builder {
private String projectName;
private String packageName;
private String gitHost;
private String gitUserId;
private String gitRepoId;
private String releaseNote;
private String httpUserAgent;
private Map<String, String> typeMappings;
private Map<String, Object> additionalProperties;
/**
* Instantiates a new Builder.
*/
public Builder() {
typeMappings = new HashMap<>();
additionalProperties = new HashMap<>();
gitHost = DEFAULT_GIT_HOST;
gitUserId = DEFAULT_GIT_USER_ID;
gitRepoId = DEFAULT_GIT_REPO_ID;
releaseNote = DEFAULT_RELEASE_NOTE;
}
public Builder withProjectName(String projectName) {
this.projectName = projectName;
return this;
}
/**
* Sets the {@code packageName} and returns a reference to this Builder so that the methods can be chained together.
*
* @param packageName the {@code packageName} to set
* @return a reference to this Builder
*/
public Builder withPackageName(String packageName) {
this.packageName = packageName;
return this;
}
/**
* Sets the {@code typeMappings} and returns a reference to this Builder so that the methods can be chained together.
*
* @param typeMappings the {@code typeMappings} to set
* @return a reference to this Builder
*/
public Builder withTypeMappings(Map<String, String> typeMappings) {
this.typeMappings = typeMappings;
return this;
}
public Builder withTypeMapping(String key, String value) {
if (this.typeMappings == null) {
this.typeMappings = new HashMap<>();
}
this.typeMappings.put(key, value);
return this;
}
/**
* Sets the {@code additionalProperties} and returns a reference to this Builder so that the methods can be chained together.
*
* @param additionalProperties the {@code additionalProperties} to set
* @return a reference to this Builder
*/
public Builder withAdditionalProperties(Map<String, Object> additionalProperties) {
this.additionalProperties = additionalProperties;
return this;
}
/**
* Sets the {@code additionalProperties} and returns a reference to this Builder so that the methods can be chained together.
*
* @param key A key for some additional property
* @param value The value of some additional property
* @return a reference to this Builder
*/
public Builder withAdditionalProperty(String key, Object value) {
if (this.additionalProperties == null) {
this.additionalProperties = new HashMap<>();
}
this.additionalProperties.put(key, value);
return this;
}
/**
* Sets the {@code gitHost} and returns a reference to this Builder so that the methods can be chained together.
*
* @param gitHost the {@code gitHost} to set
* @return a reference to this Builder
*/
public Builder withGitHost(String gitHost) {
this.gitHost = gitHost;
return this;
}
/**
* Sets the {@code gitUserId} and returns a reference to this Builder so that the methods can be chained together.
*
* @param gitUserId the {@code gitUserId} to set
* @return a reference to this Builder
*/
public Builder withGitUserId(String gitUserId) {
this.gitUserId = gitUserId;
return this;
}
/**
* Sets the {@code gitRepoId} and returns a reference to this Builder so that the methods can be chained together.
*
* @param gitRepoId the {@code gitRepoId} to set
* @return a reference to this Builder
*/
public Builder withGitRepoId(String gitRepoId) {
this.gitRepoId = gitRepoId;
return this;
}
/**
* Sets the {@code releaseNote} and returns a reference to this Builder so that the methods can be chained together.
*
* @param releaseNote the {@code releaseNote} to set
* @return a reference to this Builder
*/
public Builder withReleaseNote(String releaseNote) {
this.releaseNote = releaseNote;
return this;
}
/**
* Sets the {@code httpUserAgent} and returns a reference to this Builder so that the methods can be chained together.
*
* @param httpUserAgent the {@code httpUserAgent} to set
* @return a reference to this Builder
*/
public Builder withHttpUserAgent(String httpUserAgent) {
this.httpUserAgent = httpUserAgent;
return this;
}
/**
* Returns a {@code GeneratorSettings} built from the parameters previously set.
*
* @return a {@code GeneratorSettings} built with parameters of this {@code GeneratorSettings.Builder}
*/
public GeneratorSettings build() {
GeneratorSettings instance = new GeneratorSettings(this);
//noinspection PlaceholderCountMatchesArgumentCount
LOGGER.debug("GeneratorSettings#build: %s", instance.toString());
return instance;
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ibizlab-generator-project</artifactId>
<groupId>com.ibizlab</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.ibizlab</groupId>
<artifactId>ibizlab-generator</artifactId>
<version>1.0-SNAPSHOT</version>
<name>ibizlab-generator</name>
<dependencies>
<dependency>
<groupId>com.ibizlab</groupId>
<artifactId>ibizlab-generator-core</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.parser.util.SchemaTypeUtil;
import java.util.LinkedHashMap;
import java.util.Map;
public class CliOption {
private final String opt;
private String description;
private String type;
private String defaultValue;
private String optValue;
private Map<String, String> enumValues;
public CliOption(String opt, String description) {
this(opt, description, SchemaTypeUtil.STRING_TYPE);
}
public CliOption(String opt, String description, String type) {
this.opt = opt;
this.description = description;
this.type = type;
}
public String getOpt() {
return opt;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDefault() {
return defaultValue;
}
public void setDefault(String defaultValue) {
this.defaultValue = defaultValue;
}
public CliOption defaultValue(String defaultValue) {
this.defaultValue = defaultValue;
return this;
}
public String getOptValue() {
return this.optValue;
}
public void setOptValue(String optValue) {
if (this.enumValues!=null && this.enumValues.containsKey(optValue)) {
this.optValue = optValue;
} else {
this.optValue = null;
}
}
public CliOption addEnum(String value, String description) {
if (this.enumValues == null) {
this.enumValues = new LinkedHashMap<String, String>();
}
if (!enumValues.containsKey(value)) {
enumValues.put(value, description);
}
return this;
}
public Map<String, String> getEnum() {
return enumValues;
}
public void setEnum(Map<String, String> enumValues) {
this.enumValues = enumValues;
}
/**
* Create new boolean command line option with a default of false
*
* @param opt Option name
* @param description Option description
* @return the CliOption created
*/
public static CliOption newBoolean(String opt, String description) {
return newBoolean(opt, description, false);
}
/**
* Create new boolean command line option with the provided value as default
*
* @param opt Option name
* @param description Option description
* @param defaultValue the default value to use if option not specified
* @return the CliOption created
*/
public static CliOption newBoolean(String opt, String description, boolean defaultValue) {
return new CliOption(opt, description, SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(String.valueOf(defaultValue));
}
public static CliOption newString(String opt, String description) {
return new CliOption(opt, description, SchemaTypeUtil.STRING_TYPE);
}
@JsonIgnore
public String getOptionHelp() {
StringBuilder sb = new StringBuilder(description);
if(defaultValue != null) {
sb.append(" (Default: ").append(defaultValue).append(")");
}
if (enumValues != null) {
for (Map.Entry<String, String> entry : enumValues.entrySet()) {
sb.append("\n ").append(entry.getKey()).append(" - ").append(entry.getValue());
}
}
return sb.toString();
}
}
package com.ibizlab.codegen;
import com.ibizlab.codegen.api.TemplateDefinition;
import io.swagger.v3.parser.core.models.AuthorizationValue;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
public class ClientOptInput {
private CodegenConfig config;
private List<TemplateDefinition> userDefinedTemplates;
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Ticker;
import com.google.common.base.CaseFormat;
import com.google.common.collect.ImmutableMap;
import com.ibizlab.codegen.api.TemplateDefinition;
import com.ibizlab.codegen.api.TemplatingEngineAdapter;
import com.ibizlab.codegen.config.GeneratorSettings;
import com.ibizlab.codegen.config.GlobalSettings;
import com.ibizlab.codegen.templating.MustacheEngineAdapter;
import com.ibizlab.codegen.templating.mustache.*;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Mustache.Compiler;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.callbacks.Callback;
import io.swagger.v3.oas.models.examples.Example;
import io.swagger.v3.oas.models.headers.Header;
import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.oas.models.parameters.*;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
import io.swagger.v3.oas.models.security.OAuthFlow;
import io.swagger.v3.oas.models.security.OAuthFlows;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import io.swagger.v3.oas.models.servers.ServerVariable;
import io.swagger.v3.parser.util.SchemaTypeUtil;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.ibizlab.codegen.utils.StringAdvUtils.*;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
public class CodegenConfig {
private final Logger LOGGER = LoggerFactory.getLogger(CodegenConfig.class);
private String inputSpec;
private String outputDir;
private String templateDir;
private String auth;
private Map<String, Object> additionalProperties = new HashMap<>();
private Map<String, String> typeMappings;
private TemplatingEngineAdapter templatingEngine;
@SuppressWarnings("static-method")
public String sanitizeName(String name) {
return sanitizeName(name, "\\W");
}
private static Cache<SanitizeNameOptions, String> sanitizedNameCache;
static {
int cacheSize = Integer.parseInt(GlobalSettings.getProperty(NAME_CACHE_SIZE_PROPERTY, "500"));
int cacheExpiry = Integer.parseInt(GlobalSettings.getProperty(NAME_CACHE_EXPIRY_PROPERTY, "10"));
sanitizedNameCache = Caffeine.newBuilder()
.maximumSize(cacheSize)
.expireAfterAccess(cacheExpiry, TimeUnit.SECONDS)
.ticker(Ticker.systemTicker())
.build();
}
/**
* Sanitize name (parameter, property, method, etc)
*
* @param name string to be sanitize
* @param removeCharRegEx a regex containing all char that will be removed
* @return sanitized string
*/
public String sanitizeName(String name, String removeCharRegEx) {
return sanitizeName(name, removeCharRegEx, new ArrayList<>());
}
/**
* Sanitize name (parameter, property, method, etc)
*
* @param name string to be sanitize
* @param removeCharRegEx a regex containing all char that will be removed
* @param exceptionList a list of matches which should not be sanitized (i.e exception)
* @return sanitized string
*/
@SuppressWarnings("static-method")
public String sanitizeName(final String name, String removeCharRegEx, ArrayList<String> exceptionList) {
// NOTE: performance wise, we should have written with 2 replaceAll to replace desired
// character with _ or empty character. Below aims to spell out different cases we've
// encountered so far and hopefully make it easier for others to add more special
// cases in the future.
// better error handling when map/array type is invalid
if (name == null) {
LOGGER.error("String to be sanitized is null. Default to ERROR_UNKNOWN");
return "ERROR_UNKNOWN";
}
// if the name is just '$', map it to 'value' for the time being.
if ("$".equals(name)) {
return "value";
}
SanitizeNameOptions opts = new SanitizeNameOptions(name, removeCharRegEx, exceptionList);
return sanitizedNameCache.get(opts, sanitizeNameOptions -> {
String modifiable = sanitizeNameOptions.getName();
List<String> exceptions = sanitizeNameOptions.getExceptions();
// input[] => input
modifiable = this.sanitizeValue(modifiable, "\\[\\]", "", exceptions);
// input[a][b] => input_a_b
modifiable = this.sanitizeValue(modifiable, "\\[", "_", exceptions);
modifiable = this.sanitizeValue(modifiable, "\\]", "", exceptions);
// input(a)(b) => input_a_b
modifiable = this.sanitizeValue(modifiable, "\\(", "_", exceptions);
modifiable = this.sanitizeValue(modifiable, "\\)", "", exceptions);
// input.name => input_name
modifiable = this.sanitizeValue(modifiable, "\\.", "_", exceptions);
// input-name => input_name
modifiable = this.sanitizeValue(modifiable, "-", "_", exceptions);
// a|b => a_b
modifiable = this.sanitizeValue(modifiable, "\\|", "_", exceptions);
// input name and age => input_name_and_age
modifiable = this.sanitizeValue(modifiable, " ", "_", exceptions);
// /api/films/get => _api_films_get
// \api\films\get => _api_films_get
modifiable = modifiable.replaceAll("/", "_");
modifiable = modifiable.replaceAll("\\\\", "_");
// remove everything else other than word, number and _
// $php_variable => php_variable
modifiable = modifiable.replaceAll(sanitizeNameOptions.getRemoveCharRegEx(), "");
return modifiable;
});
}
private String sanitizeValue(String value, String replaceMatch, String replaceValue, List<String> exceptionList) {
if (exceptionList.size() == 0 || !exceptionList.contains(replaceMatch)) {
return value.replaceAll(replaceMatch, replaceValue);
}
return value;
}
/**
* Sanitize tag
*
* @param tag Tag
* @return Sanitized tag
*/
public String sanitizeTag(String tag) {
tag = camelize(sanitizeName(tag));
// tag starts with numbers
if (tag.matches("^\\d.*")) {
tag = "Class" + tag;
}
return tag;
}
private static class SanitizeNameOptions {
public SanitizeNameOptions(String name, String removeCharRegEx, List<String> exceptions) {
this.name = name;
this.removeCharRegEx = removeCharRegEx;
if (exceptions != null) {
this.exceptions = Collections.unmodifiableList(exceptions);
} else {
this.exceptions = Collections.emptyList();
}
}
public String getName() {
return name;
}
public String getRemoveCharRegEx() {
return removeCharRegEx;
}
public List<String> getExceptions() {
return exceptions;
}
private String name;
private String removeCharRegEx;
private List<String> exceptions;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SanitizeNameOptions that = (SanitizeNameOptions) o;
return Objects.equals(getName(), that.getName()) &&
Objects.equals(getRemoveCharRegEx(), that.getRemoveCharRegEx()) &&
Objects.equals(getExceptions(), that.getExceptions());
}
@Override
public int hashCode() {
return Objects.hash(getName(), getRemoveCharRegEx(), getExceptions());
}
}
}
\ No newline at end of file
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
public class CodegenConfigLoader {
/**
* Tries to load config class with SPI first, then with class name directly from classpath
*
* @param name name of config, or full qualified class name in classpath
* @return config class
*/
public static CodegenConfig forName(String name) {
ServiceLoader<CodegenConfig> loader = ServiceLoader.load(CodegenConfig.class, CodegenConfig.class.getClassLoader());
StringBuilder availableConfigs = new StringBuilder();
for (CodegenConfig config : loader) {
if (config.getName().equals(name)) {
return config;
}
availableConfigs.append(config.getName()).append("\n");
}
// else try to load directly
try {
return (CodegenConfig) Class.forName(name).getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new GeneratorNotFoundException("Can't load config class with name '".concat(name) + "'\nAvailable:\n" + availableConfigs, e);
}
}
public static List<CodegenConfig> getAll() {
ServiceLoader<CodegenConfig> loader = ServiceLoader.load(CodegenConfig.class, CodegenConfig.class.getClassLoader());
List<CodegenConfig> output = new ArrayList<CodegenConfig>();
for (CodegenConfig aLoader : loader) {
output.add(aLoader);
}
return output;
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen;
/**
* A class for storing constants that are used throughout the project.
*/
public class CodegenConstants {
/* System Properties */
// NOTE: We may want to move these to a separate class to avoid confusion or modification.
public static final String APIS = "apis";
public static final String MODELS = "models";
public static final String SUPPORTING_FILES = "supportingFiles";
public static final String MODEL_TESTS = "modelTests";
public static final String MODEL_DOCS = "modelDocs";
public static final String API_TESTS = "apiTests";
public static final String API_DOCS = "apiDocs";
public static final String WITH_XML = "withXml";
public static final String SKIP_FORM_MODEL = "skipFormModel";
/* /end System Properties */
public static final String API_PACKAGE = "apiPackage";
public static final String API_PACKAGE_DESC = "package for generated api classes";
public static final String API_SUFFIX = "apiSuffix";
public static final String API_SUFFIX_DESC = "suffix for api classes";
public static final String MODEL_PACKAGE = "modelPackage";
public static final String MODEL_PACKAGE_DESC = "package for generated models";
public static final String TEMPLATE_DIR = "templateDir";
public static final String ALLOW_UNICODE_IDENTIFIERS = "allowUnicodeIdentifiers";
public static final String ALLOW_UNICODE_IDENTIFIERS_DESC = "boolean, toggles whether unicode identifiers are allowed in names or not, default is false";
public static final String INVOKER_PACKAGE = "invokerPackage";
public static final String INVOKER_PACKAGE_DESC = "root package for generated code";
public static final String PHP_INVOKER_PACKAGE = "phpInvokerPackage";
public static final String PHP_INVOKER_PACKAGE_DESC = "root package for generated php code";
public static final String PERL_MODULE_NAME = "perlModuleName";
public static final String PERL_MODULE_NAME_DESC = "root module name for generated perl code";
public static final String MODULE_NAME = "moduleName";
public static final String MODULE_NAME_DESC = "top module name (convention: CamelCase, usually corresponding to gem name).";
public static final String GEM_NAME = "gemName";
public static final String GEM_NAME_DESC = "gem name (convention: underscore_case).";
public static final String PYTHON_PACKAGE_NAME = "pythonPackageName";
public static final String PYTHON_PACKAGE_NAME_DESC = "package name for generated python code";
public static final String PYTHON_ATTR_NONE_IF_UNSET = "pythonAttrNoneIfUnset";
public static final String PYTHON_ATTR_NONE_IF_UNSET_DESC = "when accessing unset attribute, return `None` instead of raising `ApiAttributeError`";
public static final String WITH_GO_CODEGEN_COMMENT = "withGoCodegenComment";
public static final String WITH_GO_CODEGEN_COMMENT_DESC = "whether to include Go codegen comment to disable Go Lint and collapse by default in GitHub PRs and diffs";
public static final String WITH_AWSV4_SIGNATURE_COMMENT = "withAWSV4Signature";
public static final String WITH_AWSV4_SIGNATURE_COMMENT_DESC = "whether to include AWS v4 signature support";
public static final String IS_GO_SUBMODULE = "isGoSubmodule";
public static final String IS_GO_SUBMODULE_DESC = "whether the generated Go module is a submodule";
public static final String GROUP_ID = "groupId";
public static final String GROUP_ID_DESC = "groupId in generated pom.xml";
public static final String ARTIFACT_ID = "artifactId";
public static final String ARTIFACT_ID_DESC = "artifactId in generated pom.xml. This also becomes part of the generated library's filename";
public static final String ARTIFACT_VERSION = "artifactVersion";
public static final String ARTIFACT_VERSION_DESC = "artifact version in generated pom.xml. This also becomes part of the generated library's filename";
public static final String ARTIFACT_URL = "artifactUrl";
public static final String ARTIFACT_URL_DESC = "artifact URL in generated pom.xml";
public static final String ARTIFACT_DESCRIPTION = "artifactDescription";
public static final String ARTIFACT_DESCRIPTION_DESC = "artifact description in generated pom.xml";
public static final String SCM_CONNECTION = "scmConnection";
public static final String SCM_CONNECTION_DESC = "SCM connection in generated pom.xml";
public static final String SCM_DEVELOPER_CONNECTION = "scmDeveloperConnection";
public static final String SCM_DEVELOPER_CONNECTION_DESC = "SCM developer connection in generated pom.xml";
public static final String SCM_URL = "scmUrl";
public static final String SCM_URL_DESC = "SCM URL in generated pom.xml";
public static final String DEVELOPER_NAME = "developerName";
public static final String DEVELOPER_NAME_DESC = "developer name in generated pom.xml";
public static final String DEVELOPER_EMAIL = "developerEmail";
public static final String DEVELOPER_EMAIL_DESC = "developer email in generated pom.xml";
public static final String DEVELOPER_ORGANIZATION = "developerOrganization";
public static final String DEVELOPER_ORGANIZATION_DESC = "developer organization in generated pom.xml";
public static final String DEVELOPER_ORGANIZATION_URL = "developerOrganizationUrl";
public static final String DEVELOPER_ORGANIZATION_URL_DESC = "developer organization URL in generated pom.xml";
public static final String LICENSE_NAME = "licenseName";
public static final String LICENSE_NAME_DESC = "The name of the license";
public static final String LICENSE_ID = "licenseId";
public static final String LICENSE_ID_DESC = "The identifier of the license";
public static final String LICENSE_URL = "licenseUrl";
public static final String LICENSE_URL_DESC = "The URL of the license";
public static final String SOURCE_FOLDER = "sourceFolder";
public static final String SOURCE_FOLDER_DESC = "source folder for generated code";
public static final String IMPL_FOLDER = "implFolder";
public static final String IMPL_FOLDER_DESC = "folder for generated implementation code";
public static final String SERIALIZABLE_MODEL = "serializableModel";
public static final String SERIALIZABLE_MODEL_DESC = "boolean - toggle \"implements Serializable\" for generated models";
public static final String SERIALIZE_BIG_DECIMAL_AS_STRING = "bigDecimalAsString";
public static final String SERIALIZE_BIG_DECIMAL_AS_STRING_DESC = "Treat BigDecimal values as Strings to avoid precision loss.";
public static final String LIBRARY = "library";
public static final String LIBRARY_DESC = "library template (sub-template)";
public static final String SORT_PARAMS_BY_REQUIRED_FLAG = "sortParamsByRequiredFlag";
public static final String SORT_PARAMS_BY_REQUIRED_FLAG_DESC = "Sort method arguments to place required parameters before optional parameters.";
public static final String SORT_MODEL_PROPERTIES_BY_REQUIRED_FLAG = "sortModelPropertiesByRequiredFlag";
public static final String SORT_MODEL_PROPERTIES_BY_REQUIRED_FLAG_DESC = "Sort model properties to place required parameters before optional parameters.";
public static final String PREPEND_FORM_OR_BODY_PARAMETERS = "prependFormOrBodyParameters";
public static final String PREPEND_FORM_OR_BODY_PARAMETERS_DESC = "Add form or body parameters to the beginning of the parameter list.";
public static final String USE_DATETIME_OFFSET = "useDateTimeOffset";
public static final String USE_DATETIME_OFFSET_DESC = "Use DateTimeOffset to model date-time properties";
public static final String ENSURE_UNIQUE_PARAMS = "ensureUniqueParams";
public static final String ENSURE_UNIQUE_PARAMS_DESC = "Whether to ensure parameter names are unique in an operation (rename parameters that are not).";
public static final String PROJECT_NAME = "projectName";
public static final String PACKAGE_NAME = "packageName";
public static final String PACKAGE_NAME_DESC = "package for generated classes (where supported)";
public static final String PACKAGE_VERSION = "packageVersion";
public static final String PACKAGE_TITLE = "packageTitle";
public static final String PACKAGE_TITLE_DESC = "Specifies an AssemblyTitle for the .NET Framework global assembly attributes stored in the AssemblyInfo file.";
public static final String PACKAGE_PRODUCTNAME = "packageProductName";
public static final String PACKAGE_PRODUCTNAME_DESC = "Specifies an AssemblyProduct for the .NET Framework global assembly attributes stored in the AssemblyInfo file.";
public static final String PACKAGE_DESCRIPTION = "packageDescription";
public static final String PACKAGE_DESCRIPTION_DESC = "Specifies a AssemblyDescription for the .NET Framework global assembly attributes stored in the AssemblyInfo file.";
public static final String PACKAGE_COMPANY = "packageCompany";
public static final String PACKAGE_COMPANY_DESC = "Specifies an AssemblyCompany for the .NET Framework global assembly attributes stored in the AssemblyInfo file.";
public static final String PACKAGE_AUTHORS = "packageAuthors";
public static final String PACKAGE_AUTHORS_DESC = "Specifies Authors property in the .NET Core project file.";
public static final String PACKAGE_COPYRIGHT = "packageCopyright";
public static final String PACKAGE_COPYRIGHT_DESC = "Specifies an AssemblyCopyright for the .NET Framework global assembly attributes stored in the AssemblyInfo file.";
public static final String POD_VERSION = "podVersion";
public static final String OPTIONAL_METHOD_ARGUMENT = "optionalMethodArgument";
public static final String OPTIONAL_METHOD_ARGUMENT_DESC = "Optional method argument, e.g. void square(int x=10) (.net 4.0+ only).";
public static final String OPTIONAL_ASSEMBLY_INFO = "optionalAssemblyInfo";
public static final String OPTIONAL_ASSEMBLY_INFO_DESC = "Generate AssemblyInfo.cs.";
public static final String OPTIONAL_EMIT_DEFAULT_VALUES = "optionalEmitDefaultValues";
public static final String OPTIONAL_EMIT_DEFAULT_VALUES_DESC = "Set DataMember's EmitDefaultValue.";
public static final String OPTIONAL_CONDITIONAL_SERIALIZATION = "conditionalSerialization";
public static final String OPTIONAL_CONDITIONAL_SERIALIZATION_DESC = "Serialize only those properties which are initialized by user, accepted values are true or false, default value is false.";
public static final String NETCORE_PROJECT_FILE = "netCoreProjectFile";
public static final String NETCORE_PROJECT_FILE_DESC = "Use the new format (.NET Core) for .NET project files (.csproj).";
public static final String USE_COLLECTION = "useCollection";
public static final String USE_COLLECTION_DESC = "Deserialize array types to Collection<T> instead of List<T>.";
public static final String INTERFACE_PREFIX = "interfacePrefix";
public static final String INTERFACE_PREFIX_DESC = "Prefix interfaces with a community standard or widely accepted prefix.";
public static final String RETURN_ICOLLECTION = "returnICollection";
public static final String RETURN_ICOLLECTION_DESC = "Return ICollection<T> instead of the concrete type.";
public static final String OPTIONAL_PROJECT_FILE = "optionalProjectFile";
public static final String OPTIONAL_PROJECT_FILE_DESC = "Generate {PackageName}.csproj.";
public static final String OPTIONAL_PROJECT_GUID = "packageGuid";
public static final String OPTIONAL_PROJECT_GUID_DESC = "The GUID that will be associated with the C# project";
public static final String MODEL_PROPERTY_NAMING = "modelPropertyNaming";
public static final String MODEL_PROPERTY_NAMING_DESC = "Naming convention for the property: 'camelCase', 'PascalCase', 'snake_case' and 'original', which keeps the original name";
public static final String PARAM_NAMING = "paramNaming";
public static final String PARAM_NAMING_DESC = "Naming convention for parameters: 'camelCase', 'PascalCase', 'snake_case' and 'original', which keeps the original name";
public static final String DOTNET_FRAMEWORK = "targetFramework";
public static final String DOTNET_FRAMEWORK_DESC = "The target .NET framework version. To target multiple frameworks, use `;` as the separator, e.g. `netstandard2.1;netcoreapp3.0`";
public static final String NULLABLE_REFERENCE_TYPES = "nullableReferenceTypes";
public static final String NULLABLE_REFERENCE_TYPES_DESC = "Use nullable annotations in the project. Only supported on C# 8 / ASP.NET Core 3.0 or newer.";
public static final String TEMPLATING_ENGINE = "templatingEngine";
public static final String TEMPLATING_ENGINE_DESC = "The templating engine plugin to use: \"mustache\" (default) or \"handlebars\" (beta)";
public static enum PARAM_NAMING_TYPE {camelCase, PascalCase, snake_case, original}
public static enum MODEL_PROPERTY_NAMING_TYPE {camelCase, PascalCase, snake_case, original}
public static enum ENUM_PROPERTY_NAMING_TYPE {camelCase, PascalCase, snake_case, original, UPPERCASE}
public static final String ENUM_PROPERTY_NAMING = "enumPropertyNaming";
public static final String ENUM_PROPERTY_NAMING_DESC = "Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'";
// Allow different language generators to offer an option of serialization library. Each language specific
// Codegen constants should define a description and provide proper input validation for the value of serializationLibrary
public static final String SERIALIZATION_LIBRARY = "serializationLibrary";
public static final String API_NAME_PREFIX = "apiNamePrefix";
public static final String API_NAME_PREFIX_DESC = "Prefix that will be appended to all API names ('tags'). Default: empty string. e.g. Pet => Pet.";
public static final String API_NAME_SUFFIX = "apiNameSuffix";
public static final String API_NAME_SUFFIX_DESC = "Suffix that will be appended to all API names ('tags'). Default: Api. e.g. Pet => PetApi. Note: Only ruby, python, jaxrs generators support this feature at the moment.";
public static final String MODEL_NAME_PREFIX = "modelNamePrefix";
public static final String MODEL_NAME_PREFIX_DESC = "Prefix that will be prepended to all model names.";
public static final String MODEL_NAME_SUFFIX = "modelNameSuffix";
public static final String MODEL_NAME_SUFFIX_DESC = "Suffix that will be appended to all model names.";
public static final String ENUM_NAME_SUFFIX = "enumNameSuffix";
public static final String ENUM_NAME_SUFFIX_DESC = "Suffix that will be appended to all enum names.";
public static final String ENUM_VALUE_SUFFIX = "enumValueSuffix";
public static final String ENUM_VALUE_SUFFIX_DESC = "Suffix that will be appended to all enum values. Note: For clients this may impact serialization and deserialization of enum values.";
public static final String GIT_HOST = "gitHost";
public static final String GIT_HOST_DESC = "Git host, e.g. gitlab.com.";
public static final String GIT_USER_ID = "gitUserId";
public static final String GIT_USER_ID_DESC = "Git user ID, e.g. openapitools.";
public static final String GIT_REPO_ID = "gitRepoId";
public static final String GIT_REPO_ID_DESC = "Git repo ID, e.g. openapi-generator.";
public static final String RELEASE_NOTE = "releaseNote";
public static final String RELEASE_NOTE_DESC = "Release note, default to 'Minor update'.";
public static final String HTTP_USER_AGENT = "httpUserAgent";
public static final String HTTP_USER_AGENT_DESC = "HTTP user agent, e.g. codegen_csharp_api_client, default to 'OpenAPI-Generator/{packageVersion}/{language}'";
public static final String SUPPORTS_ES6 = "supportsES6";
public static final String SUPPORTS_ES6_DESC = "Generate code that conforms to ES6.";
public static final String SUPPORTS_ASYNC = "supportsAsync";
public static final String SUPPORTS_ASYNC_DESC = "Generate code that supports async operations.";
public static final String EXCLUDE_TESTS = "excludeTests";
public static final String EXCLUDE_TESTS_DESC = "Specifies that no tests are to be generated.";
public static final String SOURCECODEONLY_GENERATION = "generateSourceCodeOnly";
public static final String SOURCECODEONLY_GENERATION_DESC = "Specifies that only a library source code is to be generated.";
public static final String PARCELIZE_MODELS = "parcelizeModels";
public static final String PARCELIZE_MODELS_DESC = "toggle \"@Parcelize\" for generated models";
public static final String CASE_INSENSITIVE_RESPONSE_HEADERS = "caseInsensitiveResponseHeaders";
public static final String CASE_INSENSITIVE_RESPONSE_HEADERS_DESC = "Make API response's headers case-insensitive";
// Not user-configurable. System provided for use in templates.
public static final String GENERATE_APIS = "generateApis";
public static final String GENERATE_API_DOCS = "generateApiDocs";
public static final String GENERATE_API_TESTS = "generateApiTests";
public static final String GENERATE_API_TESTS_DESC = "Specifies that api tests are to be generated.";
// Not user-configurable. System provided for use in templates.
public static final String GENERATE_MODELS = "generateModels";
public static final String GENERATE_MODEL_DOCS = "generateModelDocs";
public static final String VIRTUAL_SERVICE = "virtualService";
public static final String VIRTUAL_SERVICE_DESC = "Generate Spring boot rest service as virtual service with Virtualan";
public static final String GENERATE_MODEL_TESTS = "generateModelTests";
public static final String GENERATE_MODEL_TESTS_DESC = "Specifies that model tests are to be generated.";
public static final String HIDE_GENERATION_TIMESTAMP = "hideGenerationTimestamp";
public static final String HIDE_GENERATION_TIMESTAMP_DESC = "Hides the generation timestamp when files are generated.";
public static final String GENERATE_PROPERTY_CHANGED = "generatePropertyChanged";
public static final String GENERATE_PROPERTY_CHANGED_DESC = "Specifies that models support raising property changed events.";
public static final String NON_PUBLIC_API = "nonPublicApi";
public static final String NON_PUBLIC_API_DESC = "Generates code with reduced access modifiers; allows embedding elsewhere without exposing non-public API calls to consumers.";
public static final String VALIDATABLE = "validatable";
public static final String VALIDATABLE_DESC = "Generates self-validatable models.";
public static final String IGNORE_FILE_OVERRIDE = "ignoreFileOverride";
public static final String IGNORE_FILE_OVERRIDE_DESC = "Specifies an override location for the .openapi-generator-ignore file. Most useful on initial generation.";
public static final String REMOVE_OPERATION_ID_PREFIX = "removeOperationIdPrefix";
public static final String REMOVE_OPERATION_ID_PREFIX_DESC = "Remove prefix of operationId, e.g. config_getId => getId";
public static final String REMOVE_OPERATION_ID_PREFIX_DELIMITER = "removeOperationIdPrefixDelimiter";
public static final String REMOVE_OPERATION_ID_PREFIX_DELIMITER_DESC = "Character to use as a delimiter for the prefix. Default: '_'";
public static final String REMOVE_OPERATION_ID_PREFIX_COUNT = "removeOperationIdPrefixCount";
public static final String REMOVE_OPERATION_ID_PREFIX_COUNT_DESC = "Count of delimiter for the prefix. Use -1 for last Default: 1";
public static final String SKIP_OPERATION_EXAMPLE = "skipOperationExample";
public static final String SKIP_OPERATION_EXAMPLE_DESC = "Skip examples defined in operations to avoid out of memory errors.";
public static final String STRIP_PACKAGE_NAME = "stripPackageName";
public static final String STRIP_PACKAGE_NAME_DESC = "Whether to strip leading dot-separated packages from generated model classes";
public static final String DOCEXTENSION = "docExtension";
public static final String DOCEXTENSION_DESC = "The extension of the generated documentation files, defaults to markdown, .md";
public static final String DATABASE_ADAPTER = "databaseAdapter";
public static final String DATABASE_ADAPTER_DESC = "The adapter for database (e.g. mysql, sqlite). Default: sqlite";
public static final String PARENT_GROUP_ID = "parentGroupId";
public static final String PARENT_GROUP_ID_DESC = "parent groupId in generated pom N.B. parentGroupId, parentArtifactId and parentVersion must all be specified for any of them to take effect";
public static final String PARENT_ARTIFACT_ID = "parentArtifactId";
public static final String PARENT_ARTIFACT_ID_DESC = "parent artifactId in generated pom N.B. parentGroupId, parentArtifactId and parentVersion must all be specified for any of them to take effect";
public static final String PARENT_VERSION = "parentVersion";
public static final String PARENT_VERSION_DESC = "parent version in generated pom N.B. parentGroupId, parentArtifactId and parentVersion must all be specified for any of them to take effect";
public static final String ENABLE_POST_PROCESS_FILE = "enablePostProcessFile";
public static final String ENABLE_POST_PROCESS_FILE_DESC = "Enable post-processing file using environment variables.";
public static final String OPEN_API_SPEC_NAME = "openAPISpecName";
public static final String GENERATE_ALIAS_AS_MODEL = "generateAliasAsModel";
public static final String GENERATE_ALIAS_AS_MODEL_DESC = "Generate model implementation for aliases to map and array schemas. " +
"An 'alias' is an array, map, or list which is defined inline in a OpenAPI document and becomes a model in the generated code. " +
"A 'map' schema is an object that can have undeclared properties, i.e. the 'additionalproperties' attribute is set on that object. " +
"An 'array' schema is a list of sub schemas in a OAS document";
public static final String USE_COMPARE_NET_OBJECTS = "useCompareNetObjects";
public static final String USE_COMPARE_NET_OBJECTS_DESC = "Use KellermanSoftware.CompareNetObjects for deep recursive object comparison. WARNING: this option incurs potential performance impact.";
public static final String SNAPSHOT_VERSION = "snapshotVersion";
public static final String SNAPSHOT_VERSION_DESC = "Uses a SNAPSHOT version.";
public static final String EXCEPTION_ON_FAILURE = "returnExceptionOnFailure";
public static final String EXCEPTION_ON_FAILURE_DESC = "Throw an exception on non success response codes";
public static final String ENUM_CLASS_PREFIX = "enumClassPrefix";
public static final String ENUM_CLASS_PREFIX_DESC = "Prefix enum with class name";
public static final String PACKAGE_TAGS = "packageTags";
public static final String PACKAGE_TAGS_DESC = "Tags to identify the package";
public static final String REMOVE_ENUM_VALUE_PREFIX = "removeEnumValuePrefix";
public static final String REMOVE_ENUM_VALUE_PREFIX_DESC = "Remove the common prefix of enum values";
public static final String LEGACY_DISCRIMINATOR_BEHAVIOR = "legacyDiscriminatorBehavior";
public static final String LEGACY_DISCRIMINATOR_BEHAVIOR_DESC = "Set to false for generators with better support for discriminators. (Python, Java, Go, PowerShell, C#have this enabled by default).";
public static final String USE_SINGLE_REQUEST_PARAMETER = "useSingleRequestParameter";
public static final String USE_SINGLE_REQUEST_PARAMETER_DESC = "Setting this property to true will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter.";
public static final String DISALLOW_ADDITIONAL_PROPERTIES_IF_NOT_PRESENT = "disallowAdditionalPropertiesIfNotPresent";
public static final String DISALLOW_ADDITIONAL_PROPERTIES_IF_NOT_PRESENT_DESC =
"If false, the 'additionalProperties' implementation (set to true by default) is compliant with the OAS and JSON schema specifications. " +
"If true (default), keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.";
public static final String USE_ONEOF_DISCRIMINATOR_LOOKUP = "useOneOfDiscriminatorLookup";
public static final String USE_ONEOF_DISCRIMINATOR_LOOKUP_DESC = "Use the discriminator's mapping in oneOf to speed up the model lookup. IMPORTANT: Validation (e.g. one and only one match in oneOf's schemas) will be skipped.";
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen;
import com.ibizlab.codegen.api.TemplateDefinition;
import com.ibizlab.codegen.api.TemplatePathLocator;
import com.ibizlab.codegen.api.TemplateProcessor;
import com.ibizlab.codegen.api.TemplatingEngineAdapter;
import com.ibizlab.codegen.config.GlobalSettings;
import com.ibizlab.codegen.ignore.CodegenIgnoreProcessor;
import com.ibizlab.codegen.templating.CommonTemplateContentLocator;
import com.ibizlab.codegen.templating.GeneratorTemplateContentLocator;
import com.ibizlab.codegen.templating.MustacheEngineAdapter;
import com.ibizlab.codegen.templating.TemplateManagerOptions;
import com.ibizlab.codegen.utils.ImplementationVersion;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.comparator.PathFileComparator;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.validation.Schema;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.removeStart;
@Slf4j
@SuppressWarnings("rawtypes")
public class DefaultGenerator implements Generator {
private static final String METADATA_DIR = ".ibizlab-generator";
private final boolean dryRun;
protected CodegenConfig config;
protected ClientOptInput opts;
protected CodegenIgnoreProcessor ignoreProcessor;
private Boolean generateApis = null;
private Boolean generateModels = null;
private Boolean generateSupportingFiles = null;
private Boolean generateApiTests = null;
private Boolean generateApiDocumentation = null;
private Boolean generateModelTests = null;
private Boolean generateModelDocumentation = null;
private Boolean generateMetadata = true;
private String basePath;
private String basePathWithoutHost;
private String contextPath;
private Map<String, String> generatorPropertyDefaults = new HashMap<>();
protected TemplateProcessor templateProcessor = null;
private List<TemplateDefinition> userDefinedTemplates = new ArrayList<>();
public DefaultGenerator() {
this(false);
}
public DefaultGenerator(Boolean dryRun) {
this.dryRun = Boolean.TRUE.equals(dryRun);
log.info("Generating with dryRun={}", this.dryRun);
}
@SuppressWarnings("deprecation")
@Override
public Generator opts(ClientOptInput opts) {
this.opts = opts;
this.config = opts.getConfig();
List<TemplateDefinition> userFiles = opts.getUserDefinedTemplates();
if (userFiles != null) {
this.userDefinedTemplates = Collections.unmodifiableList(userFiles);
}
TemplateManagerOptions templateManagerOptions = new TemplateManagerOptions(this.config.isEnableMinimalUpdate(),this.config.isSkipOverwrite());
TemplatingEngineAdapter templatingEngine = this.config.getTemplatingEngine();
if (templatingEngine instanceof MustacheEngineAdapter) {
MustacheEngineAdapter mustacheEngineAdapter = (MustacheEngineAdapter) templatingEngine;
mustacheEngineAdapter.setCompiler(this.config.processCompiler(mustacheEngineAdapter.getCompiler()));
}
TemplatePathLocator commonTemplateLocator = new CommonTemplateContentLocator();
TemplatePathLocator generatorTemplateLocator = new GeneratorTemplateContentLocator(this.config);
this.templateProcessor = new TemplateManager(
templateManagerOptions,
templatingEngine,
new TemplatePathLocator[]{generatorTemplateLocator, commonTemplateLocator}
);
String ignoreFileLocation = this.config.getIgnoreFilePathOverride();
if (ignoreFileLocation != null) {
final File ignoreFile = new File(ignoreFileLocation);
if (ignoreFile.exists() && ignoreFile.canRead()) {
this.ignoreProcessor = new CodegenIgnoreProcessor(ignoreFile);
} else {
log.warn("Ignore file specified at {} is not valid. This will fall back to an existing ignore file if present in the output directory.", ignoreFileLocation);
}
}
if (this.ignoreProcessor == null) {
this.ignoreProcessor = new CodegenIgnoreProcessor(this.config.getOutputDir());
}
return this;
}
@Override
public List<File> generate() {
return null;
}
/**
* Retrieves an instance to the configured template processor, available after user-defined options are
* applied via {@link DefaultGenerator#opts(ClientOptInput)}.
*
* @return A configured {@link TemplateProcessor}, or null.
*/
public TemplateProcessor getTemplateProcessor() {
return templateProcessor;
}
/**
* Programmatically disable the output of .openapi-generator/VERSION, .openapi-generator-ignore,
* or other metadata files used by OpenAPI Generator.
*
* @param generateMetadata true: enable outputs, false: disable outputs
*/
@SuppressWarnings("WeakerAccess")
public void setGenerateMetadata(Boolean generateMetadata) {
this.generateMetadata = generateMetadata;
}
/**
* Set generator properties otherwise pulled from system properties.
* Useful for running tests in parallel without relying on System.properties.
*
* @param key The system property key
* @param value The system property value
*/
@SuppressWarnings("WeakerAccess")
public void setGeneratorPropertyDefault(final String key, final String value) {
this.generatorPropertyDefaults.put(key, value);
}
private Boolean getGeneratorPropertyDefaultSwitch(final String key, final Boolean defaultValue) {
String result = null;
if (this.generatorPropertyDefaults.containsKey(key)) {
result = this.generatorPropertyDefaults.get(key);
}
if (result != null) {
return Boolean.valueOf(result);
}
return defaultValue;
}
void configureGeneratorProperties() {
// allows generating only models by specifying a CSV of models to generate, or empty for all
// NOTE: Boolean.TRUE is required below rather than `true` because of JVM boxing constraints and type inference.
generateApis = GlobalSettings.getProperty(CodegenConstants.APIS) != null ? Boolean.TRUE : getGeneratorPropertyDefaultSwitch(CodegenConstants.APIS, null);
generateModels = GlobalSettings.getProperty(CodegenConstants.MODELS) != null ? Boolean.TRUE : getGeneratorPropertyDefaultSwitch(CodegenConstants.MODELS, null);
generateSupportingFiles = GlobalSettings.getProperty(CodegenConstants.SUPPORTING_FILES) != null ? Boolean.TRUE : getGeneratorPropertyDefaultSwitch(CodegenConstants.SUPPORTING_FILES, null);
if (generateApis == null && generateModels == null && generateSupportingFiles == null) {
// no specifics are set, generate everything
generateApis = generateModels = generateSupportingFiles = true;
} else {
if (generateApis == null) {
generateApis = false;
}
if (generateModels == null) {
generateModels = false;
}
if (generateSupportingFiles == null) {
generateSupportingFiles = false;
}
}
// model/api tests and documentation options rely on parent generate options (api or model) and no other options.
// They default to true in all scenarios and can only be marked false explicitly
generateModelTests = GlobalSettings.getProperty(CodegenConstants.MODEL_TESTS) != null ? Boolean.valueOf(GlobalSettings.getProperty(CodegenConstants.MODEL_TESTS)) : getGeneratorPropertyDefaultSwitch(CodegenConstants.MODEL_TESTS, true);
generateModelDocumentation = GlobalSettings.getProperty(CodegenConstants.MODEL_DOCS) != null ? Boolean.valueOf(GlobalSettings.getProperty(CodegenConstants.MODEL_DOCS)) : getGeneratorPropertyDefaultSwitch(CodegenConstants.MODEL_DOCS, true);
generateApiTests = GlobalSettings.getProperty(CodegenConstants.API_TESTS) != null ? Boolean.valueOf(GlobalSettings.getProperty(CodegenConstants.API_TESTS)) : getGeneratorPropertyDefaultSwitch(CodegenConstants.API_TESTS, true);
generateApiDocumentation = GlobalSettings.getProperty(CodegenConstants.API_DOCS) != null ? Boolean.valueOf(GlobalSettings.getProperty(CodegenConstants.API_DOCS)) : getGeneratorPropertyDefaultSwitch(CodegenConstants.API_DOCS, true);
// Additional properties added for tests to exclude references in project related files
config.additionalProperties().put(CodegenConstants.GENERATE_API_TESTS, generateApiTests);
config.additionalProperties().put(CodegenConstants.GENERATE_MODEL_TESTS, generateModelTests);
config.additionalProperties().put(CodegenConstants.GENERATE_API_DOCS, generateApiDocumentation);
config.additionalProperties().put(CodegenConstants.GENERATE_MODEL_DOCS, generateModelDocumentation);
config.additionalProperties().put(CodegenConstants.GENERATE_APIS, generateApis);
config.additionalProperties().put(CodegenConstants.GENERATE_MODELS, generateModels);
if (!generateApiTests && !generateModelTests) {
config.additionalProperties().put(CodegenConstants.EXCLUDE_TESTS, true);
}
config.processOpts();
config.additionalProperties().put("generatorVersion", ImplementationVersion.read());
config.additionalProperties().put("generatedDate", ZonedDateTime.now().toString());
config.additionalProperties().put("generatedYear", String.valueOf(ZonedDateTime.now().getYear()));
config.additionalProperties().put("generatorClass", config.getClass().getName());
config.additionalProperties().put("inputSpec", config.getInputSpec());
basePathWithoutHost = contextPath;
}
private void generateModelTests(List<File> files, Map<String, Object> models, String modelName) throws IOException {
// to generate model test files
for (Map.Entry<String, String> configModelTestTemplateFilesEntry : config.modelTestTemplateFiles().entrySet()) {
String templateName = configModelTestTemplateFilesEntry.getKey();
String suffix = configModelTestTemplateFilesEntry.getValue();
String filename = config.modelTestFileFolder() + File.separator + config.toModelTestFilename(modelName) + suffix;
if (generateModelTests) {
// do not overwrite test file that already exists (regardless of config's skipOverwrite setting)
File modelTestFile = new File(filename);
if (modelTestFile.exists()) {
this.templateProcessor.skip(modelTestFile.toPath(), "Test files never overwrite an existing file of the same name.");
} else {
File written = processTemplateToFile(models, templateName, filename, generateModelTests, CodegenConstants.MODEL_TESTS);
if (written != null) {
files.add(written);
if (config.isEnablePostProcessFile() && !dryRun) {
config.postProcessFile(written, "model-test");
}
}
}
} else if (dryRun) {
Path skippedPath = java.nio.file.Paths.get(filename);
this.templateProcessor.skip(skippedPath, "Skipped by modelTests option supplied by user.");
}
}
}
private void generateModelDocumentation(List<File> files, Map<String, Object> models, String modelName) throws IOException {
for (String templateName : config.modelDocTemplateFiles().keySet()) {
String docExtension = config.getDocExtension();
String suffix = docExtension != null ? docExtension : config.modelDocTemplateFiles().get(templateName);
String filename = config.modelDocFileFolder() + File.separator + config.toModelDocFilename(modelName) + suffix;
File written = processTemplateToFile(models, templateName, filename, generateModelDocumentation, CodegenConstants.MODEL_DOCS);
if (written != null) {
files.add(written);
if (config.isEnablePostProcessFile() && !dryRun) {
config.postProcessFile(written, "model-doc");
}
}
}
}
private void generateModel(List<File> files, Map<String, Object> models, String modelName) throws IOException {
for (String templateName : config.modelTemplateFiles().keySet()) {
String filename = config.modelFilename(templateName, modelName);
File written = processTemplateToFile(models, templateName, filename, generateModels, CodegenConstants.MODELS);
if (written != null) {
files.add(written);
if (config.isEnablePostProcessFile() && !dryRun) {
config.postProcessFile(written, "model");
}
}
}
}
protected File processTemplateToFile(Map<String, Object> templateData, String templateName, String outputFilename, boolean shouldGenerate, String skippedByOption) throws IOException {
String adjustedOutputFilename = outputFilename.replaceAll("//", "/").replace('/', File.separatorChar);
File target = new File(adjustedOutputFilename);
if (ignoreProcessor.allowsFile(target)) {
if (shouldGenerate) {
Path outDir = java.nio.file.Paths.get(this.config.getOutputDir()).toAbsolutePath();
Path absoluteTarget = target.toPath().toAbsolutePath();
if (!absoluteTarget.startsWith(outDir)) {
throw new RuntimeException(String.format(Locale.ROOT, "Target files must be generated within the output directory; absoluteTarget=%s outDir=%s", absoluteTarget, outDir));
}
return this.templateProcessor.write(templateData,templateName, target);
} else {
this.templateProcessor.skip(target.toPath(), String.format(Locale.ROOT, "Skipped by %s options supplied by user.", skippedByOption));
return null;
}
} else {
this.templateProcessor.ignore(target.toPath(), "Ignored by rule in ignore file.");
return null;
}
}
private Path absPath(File input) {
// intentionally creates a new absolute path instance, disconnected from underlying FileSystem provider of File
return java.nio.file.Paths.get(input.getAbsolutePath());
}
/**
* Generates a file at .openapi-generator/FILES to track the files created by the user's latest run.
* This is ideal for CI and regeneration of code without stale/unused files from older generations.
*
* @param files The list tracking generated files
*/
private void generateFilesMetadata(List<File> files) {
if (generateMetadata) {
try {
StringBuilder sb = new StringBuilder();
Path outDir = absPath(new File(this.config.getOutputDir()));
List<File> filesToSort = new ArrayList<>();
// Avoid side-effecting sort in this path when generateMetadata=true
files.forEach(f -> {
// We have seen NPE on CI for getPath() returning null, so guard against this (to be fixed in 5.0 template management refactor)
//noinspection ConstantConditions
if (f != null && f.getPath() != null) {
filesToSort.add(outDir.relativize(absPath(f)).normalize().toFile());
}
});
// NOTE: Don't use File.separator here as we write linux-style paths to FILES, and File.separator will
// result in incorrect match on Windows machines.
String relativeMeta = METADATA_DIR + "/VERSION";
filesToSort.sort(PathFileComparator.PATH_COMPARATOR);
filesToSort.forEach(f -> {
// some Java implementations don't honor .relativize documentation fully.
// When outDir is /a/b and the input is /a/b/c/d, the result should be c/d.
// Some implementations make the output ./c/d which seems to mix the logic
// as documented for symlinks. So we need to trim any / or ./ from the start,
// as nobody should be generating into system root and our expectation is no ./
String relativePath = removeStart(removeStart(f.toString(), "." + File.separator), File.separator);
if (File.separator.equals("\\")) {
// ensure that windows outputs same FILES format
relativePath = relativePath.replace(File.separator, "/");
}
if (!relativePath.equals(relativeMeta)) {
sb.append(relativePath).append(System.lineSeparator());
}
});
String targetFile = config.outputFolder() + File.separator + METADATA_DIR + File.separator + config.getFilesMetadataFilename();
File filesFile = this.templateProcessor.writeToFile(targetFile, sb.toString().getBytes(StandardCharsets.UTF_8));
if (filesFile != null) {
files.add(filesFile);
}
} catch (Exception e) {
log.warn("Failed to write FILES metadata to track generated files.");
}
}
}
private String removeTrailingSlash(String value) {
return StringUtils.removeEnd(value, "/");
}
}
package com.ibizlab.codegen;
import java.io.File;
import java.util.List;
public interface Generator {
Generator opts(ClientOptInput opts);
List<File> generate();
}
\ No newline at end of file
package com.ibizlab.codegen;
/**
* Typed exception exposing issues with loading generators (e.g. by name).
*/
@SuppressWarnings("unused")
public class GeneratorNotFoundException extends RuntimeException {
/**
* Constructs a new runtime exception with {@code null} as its
* detail message. The cause is not initialized, and may subsequently be
* initialized by a call to {@link #initCause}.
*/
public GeneratorNotFoundException() {
}
/**
* Constructs a new runtime exception with the specified detail message.
* The cause is not initialized, and may subsequently be initialized by a
* call to {@link #initCause}.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
*/
public GeneratorNotFoundException(String message) {
super(message);
}
/**
* Constructs a new runtime exception with the specified detail message and
* cause. <p>Note that the detail message associated with
* {@code cause} is <i>not</i> automatically incorporated in
* this runtime exception's detail message.
*
* @param message the detail message (which is saved for later retrieval
* by the {@link #getMessage()} method).
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A <code>null</code> value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public GeneratorNotFoundException(String message, Throwable cause) {
super(message, cause);
}
/**
* Constructs a new runtime exception with the specified cause and a
* detail message of <code>(cause==null ? null : cause.toString())</code>
* (which typically contains the class and detail message of
* <code>cause</code>). This constructor is useful for runtime exceptions
* that are little more than wrappers for other throwables.
*
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A <code>null</code> value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public GeneratorNotFoundException(Throwable cause) {
super(cause);
}
/**
* Constructs a new runtime exception with the specified detail
* message, cause, suppression enabled or disabled, and writable
* stack trace enabled or disabled.
*
* @param message the detail message.
* @param cause the cause. (A {@code null} value is permitted,
* and indicates that the cause is nonexistent or unknown.)
* @param enableSuppression whether or not suppression is enabled
* or disabled
* @param writableStackTrace whether or not the stack trace should
* be writable
* @since 1.7
*/
public GeneratorNotFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package com.ibizlab.codegen;
import com.ibizlab.codegen.api.TemplatePathLocator;
import com.ibizlab.codegen.api.TemplateProcessor;
import com.ibizlab.codegen.api.TemplatingEngineAdapter;
import com.ibizlab.codegen.api.TemplatingExecutor;
import com.ibizlab.codegen.templating.TemplateManagerOptions;
import com.ibizlab.codegen.templating.TemplateNotFoundException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.Scanner;
import java.util.regex.Pattern;
/**
* Manages the lookup, compilation, and writing of template files
*/
public class TemplateManager implements TemplatingExecutor, TemplateProcessor {
private final TemplateManagerOptions options;
private final TemplatingEngineAdapter engineAdapter;
private final TemplatePathLocator[] templateLoaders;
private final Logger LOGGER = LoggerFactory.getLogger(TemplateManager.class);
public TemplateManager(
TemplateManagerOptions options,
TemplatingEngineAdapter engineAdapter,
TemplatePathLocator[] templateLoaders) {
this.options = options;
this.engineAdapter = engineAdapter;
this.templateLoaders = templateLoaders;
}
private String getFullTemplateFile(String name) {
String template = Arrays.stream(this.templateLoaders)
.map(i -> i.getFullTemplatePath(name))
.filter(Objects::nonNull)
.findFirst()
.orElse("");
if (StringUtils.isEmpty(template)) {
throw new TemplateNotFoundException(name);
}
if (name == null || name.contains("..")) {
throw new IllegalArgumentException("Template location must be constrained to template directory.");
}
return template;
}
/**
* returns the template content by name
*
* @param name the template name (e.g. model.mustache)
* @return the contents of that template
*/
@Override
public String getFullTemplateContents(String name) {
return readTemplate(getFullTemplateFile(name));
}
/**
* Returns the path of a template, allowing access to the template where consuming literal contents aren't desirable or possible.
*
* @param name the template name (e.g. model.mustache)
* @return The {@link Path} to the template
*/
@Override
public Path getFullTemplatePath(String name) {
return Paths.get(getFullTemplateFile(name));
}
/**
* Gets a normalized classpath resource location according to OS-specific file separator
*
* @param name The name of the resource file/directory to find
*
* @return A normalized string according to OS-specific file separator
*/
public static String getCPResourcePath(final String name) {
if (!"/".equals(File.separator)) {
return name.replaceAll(Pattern.quote(File.separator), "/");
}
return name;
}
/**
* Reads a template's contents from the specified location
*
* @param name The location of the template
* @return The raw template contents
*/
@SuppressWarnings("java:S112")
// ignored rule java:S112 as RuntimeException is used to match previous exception type
public String readTemplate(String name) {
if (name == null || name.contains("..")) {
throw new IllegalArgumentException("Template location must be constrained to template directory.");
}
try (Reader reader = getTemplateReader(name)) {
if (reader == null) {
throw new RuntimeException("no file found");
}
try (Scanner s = new Scanner(reader).useDelimiter("\\A")) {
return s.hasNext() ? s.next() : "";
}
} catch (Exception e) {
LOGGER.error("{}", e.getMessage(), e);
}
throw new RuntimeException("can't load template " + name);
}
@SuppressWarnings({"squid:S2095", "java:S112"})
// ignored rule squid:S2095 as used in the CLI and it's required to return a reader
// ignored rule java:S112 as RuntimeException is used to match previous exception type
public Reader getTemplateReader(String name) {
try {
InputStream is = getInputStream(name);
return new InputStreamReader(is, StandardCharsets.UTF_8);
} catch (FileNotFoundException e) {
LOGGER.error(e.getMessage());
throw new RuntimeException("can't load template " + name);
}
}
private InputStream getInputStream(String name) throws FileNotFoundException {
InputStream is;
is = this.getClass().getClassLoader().getResourceAsStream(getCPResourcePath(name));
if (is == null) {
if (name == null || name.contains("..")) {
throw new IllegalArgumentException("Template location must be constrained to template directory.");
}
is = new FileInputStream(name); // May throw but never return a null value
}
return is;
}
/**
* Writes data to a compiled template
*
* @param data Input data
* @param template Input template location
* @param target The targeted file output location
*
* @return The actual file
*/
@Override
public File write(Map<String, Object> data, String template, File target) throws IOException {
if (this.engineAdapter.handlesFile(template)) {
// Only pass files with valid endings through template engine
String templateContent = this.engineAdapter.compileTemplate(this, data, template);
return writeToFile(target.getPath(), templateContent);
} else {
// Do a straight copy of the file if not listed as supported by the template engine.
InputStream is;
try {
// look up the file using the same template resolution logic the adapters would use.
String fullTemplatePath = getFullTemplateFile(template);
is = getInputStream(fullTemplatePath);
} catch (TemplateNotFoundException ex) {
is = new FileInputStream(Paths.get(template).toFile());
}
return writeToFile(target.getAbsolutePath(), IOUtils.toByteArray(is));
}
}
@Override
public void ignore(Path path, String context) {
LOGGER.info("Ignored {} ({})", path, context);
}
@Override
public void skip(Path path, String context) {
LOGGER.info("Skipped {} ({})", path, context);
}
/**
* Write String to a file, formatting as UTF-8
*
* @param filename The name of file to write
* @param contents The contents string.
* @return File representing the written file.
* @throws IOException If file cannot be written.
*/
public File writeToFile(String filename, String contents) throws IOException {
return writeToFile(filename, contents.getBytes(StandardCharsets.UTF_8));
}
/**
* Write bytes to a file
*
* @param filename The name of file to write
* @param contents The contents bytes. Typically, this is a UTF-8 formatted string.
* @return File representing the written file.
* @throws IOException If file cannot be written.
*/
@Override
public File writeToFile(String filename, byte[] contents) throws IOException {
// Use Paths.get here to normalize path (for Windows file separator, space escaping on Linux/Mac, etc)
File outputFile = Paths.get(filename).toFile();
if (this.options.isMinimalUpdate()) {
String tempFilename = filename + ".tmp";
File tempFile = null;
try {
tempFile = writeToFileRaw(tempFilename, contents);
if (!filesEqual(tempFile, outputFile)) {
LOGGER.info("writing file {}", filename);
Files.move(tempFile.toPath(), outputFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
tempFile = null;
} else {
LOGGER.info("skipping unchanged file {}", filename);
}
} finally {
if (tempFile != null && tempFile.exists()) {
try {
Files.delete(tempFile.toPath());
} catch (Exception ex) {
LOGGER.error("Error removing temporary file {}", tempFile, ex);
}
}
}
} else {
LOGGER.info("writing file {}", filename);
outputFile = writeToFileRaw(filename, contents);
}
return outputFile;
}
private File writeToFileRaw(String filename, byte[] contents) throws IOException {
// Use Paths.get here to normalize path (for Windows file separator, space escaping on Linux/Mac, etc)
File output = Paths.get(filename).toFile();
if (this.options.isSkipOverwrite() && output.exists()) {
LOGGER.info("skip overwrite of file {}", filename);
return output;
}
if (output.getParent() != null && !new File(output.getParent()).exists()) {
File parent = Paths.get(output.getParent()).toFile();
parent.mkdirs();
}
Files.write(output.toPath(), contents);
return output;
}
private boolean filesEqual(File file1, File file2) throws IOException {
return file1.exists() && file2.exists() && Arrays.equals(Files.readAllBytes(file1.toPath()), Files.readAllBytes(file2.toPath()));
}
}
/*
* 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 com.ibizlab.codegen;
import com.ibizlab.codegen.api.TemplatingEngineAdapter;
import java.util.Locale;
import java.util.ServiceLoader;
public class TemplatingEngineLoader {
private TemplatingEngineLoader() {
throw new IllegalStateException("Utility class");
}
@SuppressWarnings("java:S112") // ignore java:S112 as generic RuntimeException is acceptable here
public static TemplatingEngineAdapter byIdentifier(String id) {
ServiceLoader<TemplatingEngineAdapter> loader = ServiceLoader.load(TemplatingEngineAdapter.class, TemplatingEngineLoader.class.getClassLoader());
StringBuilder sb = new StringBuilder();
for (TemplatingEngineAdapter templatingEngineAdapter : loader) {
if (id.equals(templatingEngineAdapter.getIdentifier())) {
return templatingEngineAdapter;
}
sb.append(templatingEngineAdapter.getIdentifier()).append("\n");
}
try {
// Attempt to load skipping SPI
return (TemplatingEngineAdapter) Class.forName(id).getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException(String.format(Locale.ROOT, "Couldn't load template engine adapter %s. Available options: %n%s", id, sb), e);
}
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.config;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.guava.GuavaModule;
import com.ibizlab.codegen.*;
import com.ibizlab.codegen.api.TemplateDefinition;
import com.ibizlab.codegen.api.TemplatingEngineAdapter;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.core.util.Yaml;
import io.swagger.v3.oas.models.OpenAPI;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.*;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
/**
* A class which manages the contextual configuration for code generation.
* This includes configuring the generator, templating, and the workflow which orchestrates these.
*
* This helper also enables the deserialization of {@link GeneratorSettings} via application-specific Jackson JSON usage
* (see {@link DynamicSettings}.
*/
@SuppressWarnings("UnusedReturnValue")
public final class CodegenConfigurator {
public static final Logger LOGGER = LoggerFactory.getLogger(CodegenConfigurator.class);
private String inputSpec;
private String outputDir;
private String templateDir;
private String auth;
private String generatorName;
private String templatingEngineName;
private Map<String, String> globalProperties = new HashMap<>();
private Map<String, Object> additionalProperties = new HashMap<>();
private GeneratorSettings generatorSettings=new GeneratorSettings();
private List<TemplateDefinition> userDefinedTemplates = new ArrayList<>();
public CodegenConfigurator() {
}
@SuppressWarnings("DuplicatedCode")
public static CodegenConfigurator fromFile(String configFile, Module... modules) {
if (isNotEmpty(configFile)) {
DynamicSettings settings = readDynamicSettings(configFile, modules);
CodegenConfigurator configurator = new CodegenConfigurator();
GeneratorSettings generatorSettings = settings.getGeneratorSettings();
List<TemplateDefinition> userDefinedTemplateSettings = settings.getFiles();
if(generatorSettings.getAdditionalProperties() != null) {
configurator.additionalProperties.putAll(generatorSettings.getAdditionalProperties());
}
if (userDefinedTemplateSettings != null) {
configurator.userDefinedTemplates.addAll(userDefinedTemplateSettings);
}
return configurator;
}
return null;
}
private static DynamicSettings readDynamicSettings(String configFile, Module... modules) {
ObjectMapper mapper;
if (FilenameUtils.isExtension(configFile.toLowerCase(Locale.ROOT), new String[]{"yml", "yaml"})) {
mapper = Yaml.mapper().copy();
} else {
mapper = Json.mapper().copy();
}
if (modules != null && modules.length > 0) {
mapper.registerModules(modules);
}
mapper.registerModule(new GuavaModule());
try {
return mapper.readValue(new File(configFile), DynamicSettings.class);
} catch (IOException ex) {
LOGGER.error(ex.getMessage());
throw new RuntimeException("Unable to deserialize config file: " + configFile);
}
}
public CodegenConfigurator addAdditionalProperty(String key, Object value) {
this.additionalProperties.put(key, value);
generatorSettings.getAdditionalProperties().put(key, value);
return this;
}
public CodegenConfigurator addGlobalProperty(String key, String value) {
this.globalProperties.put(key, value);
return this;
}
public CodegenConfigurator setAdditionalProperties(Map<String, Object> additionalProperties) {
this.additionalProperties = additionalProperties;
generatorSettings.setAdditionalProperties(additionalProperties);
return this;
}
public CodegenConfigurator setProjectName(String projectName) {
if (StringUtils.isNotEmpty(projectName)) {
addAdditionalProperty(CodegenConstants.PROJECT_NAME, projectName);
}
generatorSettings.setProjectName(projectName);
return this;
}
public CodegenConfigurator setAuth(String auth) {
// do not cache this in additional properties.
this.auth = auth;
return this;
}
public CodegenConfigurator setGitRepoId(String gitRepoId) {
if (StringUtils.isNotEmpty(gitRepoId)) {
addAdditionalProperty(CodegenConstants.GIT_REPO_ID, gitRepoId);
}
generatorSettings.setGitRepoId(gitRepoId);
return this;
}
public CodegenConfigurator setGitHost(String gitHost) {
if (StringUtils.isNotEmpty(gitHost)) {
addAdditionalProperty(CodegenConstants.GIT_HOST, gitHost);
}
generatorSettings.setGitHost(gitHost);
return this;
}
public CodegenConfigurator setGitUserId(String gitUserId) {
if (StringUtils.isNotEmpty(gitUserId)) {
addAdditionalProperty(CodegenConstants.GIT_USER_ID, gitUserId);
}
generatorSettings.setGitUserId(gitUserId);
return this;
}
public CodegenConfigurator setReleaseNote(String releaseNote) {
if (StringUtils.isNotEmpty(releaseNote)) {
addAdditionalProperty(CodegenConstants.RELEASE_NOTE, releaseNote);
}
generatorSettings.setReleaseNote(releaseNote);
return this;
}
public CodegenConfigurator setHttpUserAgent(String httpUserAgent) {
if (StringUtils.isNotEmpty(httpUserAgent)) {
addAdditionalProperty(CodegenConstants.HTTP_USER_AGENT, httpUserAgent);
}
generatorSettings.setHttpUserAgent(httpUserAgent);
return this;
}
public CodegenConfigurator setInputSpec(String inputSpec) {
this.inputSpec = inputSpec;
return this;
}
public CodegenConfigurator setOutputDir(String outputDir) {
this.outputDir = outputDir;
return this;
}
public CodegenConfigurator setPackageName(String packageName) {
if (StringUtils.isNotEmpty(packageName)) {
addAdditionalProperty(CodegenConstants.PACKAGE_NAME, packageName);
}
generatorSettings.setPackageName(packageName);
return this;
}
public CodegenConfigurator setGlobalProperties(Map<String, String> globalProperties) {
this.globalProperties = globalProperties;
return this;
}
public CodegenConfigurator setTemplateDir(String templateDir) {
this.templateDir = templateDir;
return this;
}
public ClientOptInput toClientOptInput() {
// We load the config via generatorSettings.getGeneratorName() because this is guaranteed to be set
// regardless of entrypoint (CLI sets properties on this type, config deserialization sets on generatorSettings).
CodegenConfig config = new CodegenConfig();
// TODO: Work toward CodegenConfig having a "WorkflowSettings" property, or better a "Workflow" object which itself has a "WorkflowSettings" property.
TemplatingEngineAdapter templatingEngine = TemplatingEngineLoader.byIdentifier(this.templatingEngineName);
config.setTemplatingEngine(templatingEngine);
config.getAdditionalProperties().putAll(this.additionalProperties);
config.getAdditionalProperties().putAll(this.globalProperties);
config.setInputSpec(this.inputSpec);
config.setOutputDir(this.outputDir);
config.setTemplateDir(this.templateDir);
config.setAuth(this.auth);
ClientOptInput input = new ClientOptInput()
.setConfig(config)
.setUserDefinedTemplates(userDefinedTemplates);
return input;
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.config;
import com.ibizlab.codegen.utils.OptionUtils;
import org.apache.commons.lang3.tuple.Pair;
import java.util.*;
/**
* Contains shared logic for applying key-value pairs and CSV strings
* to specific settings in CodegenConfigurator.
*
* <p>
* This class exists to facilitate testing. These methods could be applied
* to CodegenConfigurator, but this complicates things when mocking CodegenConfigurator.
* </p>
* <ul>
* <li>The methods named {@code apply...Kvp} take a string of comma-separated key-value pairs.</li>
* <li>The methods named {@code apply...KvpList} take a list of such strings.</li>
* <li>The method named {@code apply...Csv} takes a string of comma-separated values.</li>
* <li>The method named {@code apply...CsvList} takes a list of such strings.</li>
* </ul>
* <p>
* The corresponding {@code add...} method on the passed configurator is called for each key-value pair (or value).
* </p>
*/
public final class CodegenConfiguratorUtils {
public static void applyGlobalPropertiesKvpList(List<String> globalProperties, CodegenConfigurator configurator) {
for(String propString : globalProperties) {
applyGlobalPropertiesKvp(propString, configurator);
}
}
public static void applyGlobalPropertiesKvp(String globalProperties, CodegenConfigurator configurator) {
final Map<String, String> map = createMapFromKeyValuePairs(globalProperties);
for (Map.Entry<String, String> entry : map.entrySet()) {
configurator.addGlobalProperty(entry.getKey(), entry.getValue().replace(":",","));
}
}
public static void applyAdditionalPropertiesKvpList(List<String> additionalProperties, CodegenConfigurator configurator) {
for(String propString : additionalProperties) {
applyAdditionalPropertiesKvp(propString, configurator);
}
}
public static void applyAdditionalPropertiesKvp(String additionalProperties, CodegenConfigurator configurator) {
final Map<String, String> map = createMapFromKeyValuePairs(additionalProperties);
for (Map.Entry<String, String> entry : map.entrySet()) {
configurator.addAdditionalProperty(entry.getKey(), entry.getValue());
}
}
private static Set<String> createSetFromCsvList(String csvProperty) {
final List<String> values = OptionUtils.splitCommaSeparatedList(csvProperty);
return new HashSet<String>(values);
}
private static Map<String, String> createMapFromKeyValuePairs(String commaSeparatedKVPairs) {
final List<Pair<String, String>> pairs = OptionUtils.parseCommaSeparatedTuples(commaSeparatedKVPairs);
Map<String, String> result = new HashMap<String, String>();
for (Pair<String, String> pair : pairs) {
result.put(pair.getLeft(), pair.getRight());
}
return result;
}
}
package com.ibizlab.codegen.config;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.ibizlab.codegen.api.TemplateDefinition;
import com.ibizlab.codegen.api.TemplateFileType;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
public class DynamicSettings {
@JsonAnySetter
private Map<String, Object> dynamicProperties = new HashMap<>();
@JsonUnwrapped
@JsonDeserialize(builder = GeneratorSettings.Builder.class)
private GeneratorSettings generatorSettings;
/**
* Gets the list of template files allowing user redefinition and addition of templating files
*
* @return A list of template files
*/
public List<TemplateDefinition> getFiles() {
if (files == null) return new ArrayList<>();
return files.entrySet().stream().map(kvp -> {
TemplateDefinition file = kvp.getValue();
String templateFile = kvp.getKey();
String destination = file.getDestinationFilename();
if (TemplateFileType.SupportingFiles.equals(file.getTemplateType()) && StringUtils.isBlank(destination)) {
// this special case allows definitions such as LICENSE:{}
destination = templateFile;
}
TemplateDefinition definition = new TemplateDefinition(templateFile, file.getFolder(), destination);
definition.setTemplateType(file.getTemplateType());
return definition;
}).collect(Collectors.toList());
}
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
@JsonProperty("files")
private Map<String, TemplateDefinition> files;
public GeneratorSettings getGeneratorSettings() {
excludeSettingsFromDynamicProperties();
GeneratorSettings.Builder builder = GeneratorSettings.newBuilder(generatorSettings);
// This allows us to put any unknown top-level properties into additionalProperties of the generator object.
for (Map.Entry<String, Object> entry : dynamicProperties.entrySet()) {
builder.withAdditionalProperty(entry.getKey(), entry.getValue());
}
return builder.build();
}
/**
* <p>Constructor for DynamicSettings.</p>
*/
@JsonCreator
public DynamicSettings() { }
/**
* Gets all "custom" properties included in the config object.
*
* @return All user-specified custom properties.
*/
public Map<String, Object> getDynamicProperties() {
return dynamicProperties;
}
private void excludeSettingsFromDynamicProperties(){
Set<String> fieldNames = new HashSet<>();
for (Field field : GeneratorSettings.class.getDeclaredFields()) {
fieldNames.add(field.getName());
}
dynamicProperties.keySet().removeAll(fieldNames);
}
}
package com.ibizlab.codegen.config;
import java.util.Properties;
public class GlobalSettings {
private static ThreadLocal<Properties> properties = new InheritableThreadLocal<Properties>() {
@Override
protected Properties initialValue() {
// avoid using System.getProperties().clone() which is broken in Gradle - see https://github.com/gradle/gradle/issues/17344
Properties copy = new Properties();
copy.putAll(System.getProperties());
return copy;
};
};
public static String getProperty(String key, String defaultValue) {
return properties.get().getProperty(key, defaultValue);
}
public static String getProperty(String key) {
return properties.get().getProperty(key);
}
public static void setProperty(String key, String value) {
properties.get().setProperty(key, value);
}
public static void clearProperty(String key) {
properties.get().remove(key);
}
public static void reset() {
properties.remove();
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.ignore;
import com.ibizlab.codegen.ignore.rules.DirectoryRule;
import com.ibizlab.codegen.ignore.rules.Rule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
/**
* Presents a processing utility for parsing and evaluating files containing common ignore patterns. (.openapi-generator-ignore)
*/
public class CodegenIgnoreProcessor {
private final Logger LOGGER = LoggerFactory.getLogger(CodegenIgnoreProcessor.class);
private File ignoreFile = null;
private List<Rule> exclusionRules = new ArrayList<>();
private List<Rule> inclusionRules = new ArrayList<>();
/**
* Loads the default ignore file (.openapi-generator-ignore) from the specified path.
*
* @param baseDirectory The base directory of the files to be processed. This contains the ignore file.
*/
public CodegenIgnoreProcessor(final String baseDirectory) {
this(baseDirectory, ".openapi-generator-ignore");
}
/**
* Loads the specified ignore file by name ([ignoreFile]) from the specified path.
*
* @param baseDirectory The base directory of the files to be processed. This contains the ignore file.
* @param ignoreFile The file containing ignore patterns.
*/
@SuppressWarnings("WeakerAccess")
public CodegenIgnoreProcessor(final String baseDirectory, final String ignoreFile) {
final File directory = new File(baseDirectory);
final File targetIgnoreFile = new File(directory, ignoreFile);
if (directory.exists() && directory.isDirectory()) {
loadFromFile(targetIgnoreFile);
} else {
LOGGER.info("Output directory ({}) does not exist, or is inaccessible. No file (.openapi-generator-ignore) will be evaluated.", baseDirectory);
}
}
/**
* Constructs an instance of {@link CodegenIgnoreProcessor} from an ignore file defined by {@code targetIgnoreFile}.
*
* @param targetIgnoreFile The ignore file location.
*/
public CodegenIgnoreProcessor(final File targetIgnoreFile) {
loadFromFile(targetIgnoreFile);
}
private void loadFromFile(File targetIgnoreFile) {
if (targetIgnoreFile.exists() && targetIgnoreFile.isFile()) {
try {
loadCodegenRules(targetIgnoreFile);
this.ignoreFile = targetIgnoreFile;
} catch (IOException e) {
LOGGER.error(String.format(Locale.ROOT, "Could not process %s.", targetIgnoreFile.getName()), e.getMessage());
}
} else if (!".swagger-codegen-ignore".equals(targetIgnoreFile.getName())) {
final File legacyIgnoreFile = new File(targetIgnoreFile.getParentFile(), ".swagger-codegen-ignore");
if (legacyIgnoreFile.exists() && legacyIgnoreFile.isFile()) {
LOGGER.info(String.format(Locale.ROOT, "Legacy support: '%s' file renamed to '%s'.", legacyIgnoreFile.getName(), targetIgnoreFile.getName()));
try {
Files.move(legacyIgnoreFile.toPath(), targetIgnoreFile.toPath(), REPLACE_EXISTING);
loadFromFile(targetIgnoreFile);
} catch (IOException e) {
LOGGER.error(String.format(Locale.ROOT, "Could not rename file: %s", e.getMessage()));
}
} else {
// log info message
LOGGER.info(String.format(Locale.ROOT, "No %s file found.", targetIgnoreFile.getName()));
}
} else {
// log info message
LOGGER.info(String.format(Locale.ROOT, "No %s file found.", targetIgnoreFile.getName()));
}
}
void loadCodegenRules(final File codegenIgnore) throws IOException {
try (FileInputStream fileInputStream = new FileInputStream(codegenIgnore);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
BufferedReader reader = new BufferedReader(inputStreamReader)) {
String line;
// NOTE: Comments that start with a : (e.g. //:) are pulled from git documentation for .gitignore
// see: https://github.com/git/git/blob/90f7b16b3adc78d4bbabbd426fb69aa78c714f71/Documentation/gitignore.txt
while ((line = reader.readLine()) != null) {
if(
//: A blank line matches no files, so it can serve as a separator for readability.
line.length() == 0
) continue;
Rule rule = Rule.create(line);
// rule could be null here if it's a COMMENT, for example
if(rule != null) {
if (Boolean.TRUE.equals(rule.getNegated())) {
inclusionRules.add(rule);
} else {
exclusionRules.add(rule);
}
}
}
}
}
/**
* Determines whether or not a file defined by {@code toEvaluate} is allowed,
* under the exclusion rules from the ignore file being processed.
*
* @param targetFile The file to check against exclusion rules from the ignore file.
* @return {@code false} if file matches any pattern in the ignore file (disallowed), otherwise {@code true} (allowed).
*/
public boolean allowsFile(final File targetFile) {
if(this.ignoreFile == null) return true;
File file = new File(this.ignoreFile.getAbsoluteFile().getParentFile().toURI().relativize(targetFile.toURI()).getPath());
boolean directoryExcluded = false;
boolean exclude = false;
if(exclusionRules.size() == 0 && inclusionRules.size() == 0) {
return true;
}
// NOTE: We *must* process all exclusion rules
for (int i = 0; i < exclusionRules.size(); i++) {
Rule current = exclusionRules.get(i);
Rule.Operation op = current.evaluate(file.getPath());
switch (op){
case EXCLUDE:
exclude = true;
// Include rule can't override rules that exclude a file by some parent directory.
if(current instanceof DirectoryRule) {
directoryExcluded = true;
}
break;
case INCLUDE:
// This won't happen here.
break;
case NOOP:
break;
case EXCLUDE_AND_TERMINATE:
i = exclusionRules.size();
break;
}
}
if(exclude) {
// Only need to process inclusion rules if we've been excluded
for (int i = 0; exclude && i < inclusionRules.size(); i++) {
Rule current = inclusionRules.get(i);
Rule.Operation op = current.evaluate(file.getPath());
// At this point exclude=true means the file should be ignored.
// op == INCLUDE means we have to flip that flag.
if(op.equals(Rule.Operation.INCLUDE)) {
if(current instanceof DirectoryRule && directoryExcluded) {
// e.g
// baz/
// !foo/bar/baz/
// NOTE: Possibly surprising side effect:
// foo/bar/baz/
// !bar/
exclude = false;
} else if (!directoryExcluded) {
// e.g.
// **/*.log
// !ISSUE_1234.log
exclude = false;
}
}
}
}
return Boolean.FALSE.equals(exclude);
}
/**
* Allows a consumer to manually inspect explicit "inclusion rules". That is, patterns in the ignore file which have been negated.
*
* @return A {@link Collections#unmodifiableList(List)} of rules which possibly negate exclusion rules in the ignore file.
*/
public List<Rule> getInclusionRules() {
return Collections.unmodifiableList(inclusionRules);
}
/**
* Allows a consumer to manually inspect all "exclusion rules". That is, patterns in the ignore file which represent
* files and directories to be excluded, unless explicitly overridden by {@link CodegenIgnoreProcessor#getInclusionRules()} rules.
*
* NOTE: Existence in this list doesn't mean a file is excluded. The rule can be overridden by {@link CodegenIgnoreProcessor#getInclusionRules()} rules.
*
* @return A {@link Collections#unmodifiableList(List)} of rules which define exclusions by patterns in the ignore file.
*/
public List<Rule> getExclusionRules() {
return Collections.unmodifiableList((exclusionRules));
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.ignore.rules;
import java.nio.file.FileSystems;
import java.nio.file.PathMatcher;
import java.util.List;
public class DirectoryRule extends FileRule {
private PathMatcher directoryMatcher = null;
private PathMatcher contentsMatcher = null;
DirectoryRule(List<Part> syntax, String definition) {
super(syntax, definition);
String pattern = this.getPattern();
StringBuilder sb = new StringBuilder();
sb.append("glob:");
sb.append(pattern);
if(!pattern.endsWith("/")) sb.append("/");
directoryMatcher = FileSystems.getDefault().getPathMatcher(sb.toString());
sb.append("**");
contentsMatcher = FileSystems.getDefault().getPathMatcher(sb.toString());
}
@Override
public Boolean matches(String relativePath) {
return contentsMatcher.matches(FileSystems.getDefault().getPath(relativePath)) || directoryMatcher.matches(FileSystems.getDefault().getPath(relativePath));
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.ignore.rules;
import java.util.List;
/**
* An ignore rule which matches everything.
*/
public class EverythingRule extends Rule {
EverythingRule(List<Part> syntax, String definition) {
super(syntax, definition);
}
@Override
public Boolean matches(String relativePath) {
return true;
}
@Override
protected Operation getExcludeOperation(){ return Operation.EXCLUDE_AND_TERMINATE; }
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.ignore.rules;
import java.nio.file.FileSystems;
import java.nio.file.PathMatcher;
import java.util.List;
public class FileRule extends Rule {
private PathMatcher matcher = null;
FileRule(List<Part> syntax, String definition) {
super(syntax, definition);
matcher = FileSystems.getDefault().getPathMatcher("glob:"+this.getPattern());
}
@Override
public Boolean matches(String relativePath) {
return matcher.matches(FileSystems.getDefault().getPath(relativePath));
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.ignore.rules;
import java.util.ArrayList;
import java.util.List;
public class IgnoreLineParser {
enum Token {
MATCH_ALL("**"),
MATCH_ANY("*"),
ESCAPED_EXCLAMATION("\\!"),
ESCAPED_SPACE("\\ "),
PATH_DELIM("/"),
NEGATE("!"),
TEXT(null),
DIRECTORY_MARKER("/"),
ROOTED_MARKER("/"),
COMMENT(null);
private String pattern;
Token(String pattern) {
this.pattern = pattern;
}
public String getPattern() {
return pattern;
}
}
// NOTE: Comments that start with a : (e.g. //:) are pulled from git documentation for .gitignore
// see: https://github.com/git/git/blob/90f7b16b3adc78d4bbabbd426fb69aa78c714f71/Documentation/gitignore.txt
static List<Part> parse(String text) throws ParserException {
List<Part> parts = new ArrayList<>();
StringBuilder sb = new StringBuilder();
String current = null;
String next = null;
char[] characters = text.toCharArray();
for (int i = 0, totalLength = characters.length; i < totalLength; i++) {
char character = characters[i];
current = String.valueOf(character);
next = i < totalLength - 1 ? String.valueOf(characters[i + 1]) : null;
if (i == 0) {
if ("#".equals(current)) {
//: A line starting with # serves as a comment.
parts.add(new Part(Token.COMMENT, text));
i = totalLength; // rather than early return
continue;
} else if ("!".equals(current)) {
if (i == totalLength - 1) {
throw new ParserException("Negation with no negated pattern.");
} else {
parts.add(new Part(Token.NEGATE));
continue;
}
} else if ("\\".equals(current) && "#".equals(next)) {
//: Put a backslash ("`\`") in front of the first hash for patterns
//: that begin with a hash.
// NOTE: Just push forward and drop the escape character. Falls through to TEXT token.
current = next;
next = null;
i++;
}
}
if (Token.MATCH_ANY.pattern.equals(current)) {
if (Token.MATCH_ANY.pattern.equals(next)) {
// peek ahead for invalid pattern. Slightly inefficient, but acceptable.
if ((i+2 < totalLength - 1) &&
String.valueOf(characters[i+2]).equals(Token.MATCH_ANY.pattern)) {
// It doesn't matter where we are in the pattern, *** is invalid.
throw new ParserException("The pattern *** is invalid.");
}
parts.add(new Part(Token.MATCH_ALL));
i++;
continue;
} else {
if (sb.length() > 0) {
// A MATCH_ANY may commonly follow a filename or some other character. Dump that to results before the MATCH_ANY.
parts.add(new Part(Token.TEXT, sb.toString()));
sb.delete(0, sb.length());
}
parts.add(new Part(Token.MATCH_ANY));
continue;
}
}
if (i == 0 && Token.ROOTED_MARKER.pattern.equals(current)) {
parts.add(new Part(Token.ROOTED_MARKER));
continue;
}
if ("\\".equals(current) && " ".equals(next)) {
parts.add(new Part(Token.ESCAPED_SPACE));
i++;
continue;
} else if ("\\".equals(current) && "!".equals(next)) {
parts.add(new Part(Token.ESCAPED_EXCLAMATION));
i++;
continue;
}
if (Token.PATH_DELIM.pattern.equals(current)) {
if (i != totalLength - 1) {
if (sb.length() > 0) {
parts.add(new Part(Token.TEXT, sb.toString()));
sb.delete(0, sb.length());
}
parts.add(new Part(Token.PATH_DELIM));
if(Token.PATH_DELIM.pattern.equals(next)) {
// ignore doubled path delims. NOTE: doesn't do full lookahead, so /// will result in //
i++;
}
continue;
} else if (i == totalLength - 1) {
parts.add(new Part(Token.TEXT, sb.toString()));
sb.delete(0, sb.length());
parts.add(new Part(Token.DIRECTORY_MARKER));
continue;
}
}
sb.append(current);
}
if (sb.length() > 0) {
// NOTE: All spaces escaped spaces are a special token, ESCAPED_SPACE
//: Trailing spaces are ignored unless they are quoted with backslash ("`\`")
parts.add(new Part(Token.TEXT, sb.toString().trim()));
}
return parts;
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.ignore.rules;
import java.util.List;
public class InvalidRule extends Rule {
private final String reason;
InvalidRule(List<Part> syntax, String definition, String reason) {
super(syntax, definition);
this.reason = reason;
}
@Override
public Boolean matches(String relativePath) {
return null;
}
@Override
public Operation evaluate(String relativePath) {
return Operation.NOOP;
}
public String getReason() {
return reason;
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.ignore.rules;
public class ParserException extends Exception {
/**
* Constructs a new exception with the specified detail message. The
* cause is not initialized, and may subsequently be initialized by
* a call to {@link #initCause}.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
*/
public ParserException(String message) {
super(message);
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.ignore.rules;
class Part {
private final IgnoreLineParser.Token token;
private final String value;
public Part(IgnoreLineParser.Token token, String value) {
this.token = token;
this.value = value;
}
public Part(IgnoreLineParser.Token token) {
this.token = token;
this.value = token.getPattern();
}
public IgnoreLineParser.Token getToken() {
return token;
}
public String getValue() {
return value;
}
}
\ No newline at end of file
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.ignore.rules;
import java.util.List;
import java.util.regex.Pattern;
/**
* A special case rule which matches files only if they're located
* in the same directory as the .openapi-generator-ignore file.
*/
public class RootedFileRule extends Rule {
private String definedFilename = null;
private String definedExtension = null;
RootedFileRule(List<Part> syntax, String definition) {
super(syntax, definition);
int separatorIndex = definition.lastIndexOf(".");
definedFilename = getFilenamePart(definition, separatorIndex);
definedExtension = getExtensionPart(definition, separatorIndex);
}
private String getFilenamePart(final String input, int stopIndex){
return input.substring('/' == input.charAt(0) ? 1 : 0, stopIndex > 0 ? stopIndex : input.length());
}
private String getExtensionPart(final String input, int stopIndex) {
return input.substring(stopIndex > 0 ? stopIndex+1: input.length());
}
@Override
public Boolean matches(String relativePath) {
// NOTE: Windows-style separator isn't supported, so File.pathSeparator would be incorrect here.
// NOTE: lastIndexOf rather than contains because /file.txt is acceptable while path/file.txt is not.
// relativePath will be passed by CodegenIgnoreProcessor and is relative to .codegen-ignore.
boolean isSingleFile = relativePath.lastIndexOf("/") <= 0;
if(isSingleFile) {
int separatorIndex = relativePath.lastIndexOf(".");
final String filename = getFilenamePart(relativePath, separatorIndex);
final String extension = getExtensionPart(relativePath, separatorIndex);
boolean extensionMatches = definedExtension.equals(extension) || definedExtension.equals(IgnoreLineParser.Token.MATCH_ANY.getPattern());
if(extensionMatches && definedFilename.contains(IgnoreLineParser.Token.MATCH_ANY.getPattern())) {
// TODO: Evaluate any other escape requirements here.
Pattern regex = Pattern.compile(
definedFilename
.replaceAll(Pattern.quote("."), "\\\\Q.\\\\E")
.replaceAll(Pattern.quote("*"), ".*?") // non-greedy match on 0+ any character
);
return regex.matcher(filename).matches();
}
return extensionMatches && definedFilename.equals(filename);
}
return false;
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.ignore.rules;
import java.util.List;
public abstract class Rule {
public enum Operation {EXCLUDE, INCLUDE, NOOP, EXCLUDE_AND_TERMINATE}
// The original rule
private final String definition;
private final List<Part> syntax;
Rule(List<Part> syntax, String definition) {
this.syntax = syntax;
this.definition = definition;
}
public abstract Boolean matches(String relativePath);
public String getDefinition() {
return this.definition;
}
protected String getPattern() {
if(syntax == null) return this.definition;
StringBuilder sb = new StringBuilder();
for (Part current : syntax) {
switch (current.getToken()) {
case MATCH_ALL:
case MATCH_ANY:
case ESCAPED_EXCLAMATION:
case ESCAPED_SPACE:
case PATH_DELIM:
case TEXT:
case DIRECTORY_MARKER:
sb.append(current.getValue());
break;
case NEGATE:
case ROOTED_MARKER:
case COMMENT:
break;
}
}
return sb.toString();
}
/**
* Whether or not the rule should be negated. !foo means foo should be removed from previous matches.
* Example: **\/*.bak excludes all backup. Adding !/test.bak will include test.bak in the project root.
* <p>
* NOTE: It is not possible to re-include a file if a parent directory of that file is excluded.
*
* @return {@code true} if the rule is negated (inverse), otherwise {@code false} (normal).
*/
public Boolean getNegated() {
return this.syntax != null && this.syntax.size() > 0 && this.syntax.get(0).getToken() == IgnoreLineParser.Token.NEGATE;
}
public Operation evaluate(String relativePath) {
if (Boolean.TRUE.equals(matches(relativePath))) {
if(Boolean.TRUE.equals(this.getNegated())) {
return this.getIncludeOperation();
}
return this.getExcludeOperation();
}
return Operation.NOOP;
}
protected Operation getIncludeOperation(){ return Operation.INCLUDE; }
protected Operation getExcludeOperation(){ return Operation.EXCLUDE; }
public static Rule create(String definition) {
// NOTE: Comments that start with a : (e.g. //:) are pulled from git documentation for .gitignore
// see: https://github.com/git/git/blob/90f7b16b3adc78d4bbabbd426fb69aa78c714f71/Documentation/gitignore.txt
Rule rule = null;
if (definition.equals(".")) {
return new InvalidRule(null, definition, "Pattern '.' is invalid.");
} else if (definition.equals("!.")) {
return new InvalidRule(null, definition, "Pattern '!.' is invalid.");
} else if (definition.startsWith("..")) {
return new InvalidRule(null, definition, "Pattern '..' is invalid.");
}
try {
List<Part> result = IgnoreLineParser.parse(definition);
Boolean directoryOnly = null;
if (result.size() == 0) {
return rule;
} else if (result.size() == 1) {
// single-character filename only
Part part = result.get(0);
if (IgnoreLineParser.Token.MATCH_ANY.equals(part.getToken())) {
rule = new RootedFileRule(result, definition);
} else {
rule = new FileRule(result, definition);
}
} else {
IgnoreLineParser.Token head = result.get(0).getToken();
//: An optional prefix "`!`" which negates the pattern; any
//: matching file excluded by a previous pattern will become
//: included again. It is not possible to re-include a file if a parent
//: directory of that file is excluded. Git doesn't list excluded
//: directories for performance reasons, so any patterns on contained
//: files have no effect, no matter where they are defined.
//: Put a backslash ("`\`") in front of the first "`!`" for patterns
//: that begin with a literal "`!`", for example, "`\!important!.txt`".
// see this.getNegated();
//: If the pattern ends with a slash, it is removed for the
//: purpose of the following description, but it would only find
//: a match with a directory. In other words, `foo/` will match a
//: directory `foo` and paths underneath it, but will not match a
//: regular file or a symbolic link `foo` (this is consistent
//: with the way how pathspec works in general in Git).
directoryOnly = IgnoreLineParser.Token.DIRECTORY_MARKER.equals(result.get(result.size() - 1).getToken());
if (directoryOnly) {
rule = new DirectoryRule(result, definition);
} else if (IgnoreLineParser.Token.PATH_DELIM.equals(head)) {
//: A leading slash matches the beginning of the pathname.
//: For example, "/{asterisk}.c" matches "cat-file.c" but not
//: "mozilla-sha1/sha1.c".
rule = new RootedFileRule(result, definition);
} else {
// case 1
//: If the pattern does not contain a slash '/', Git treats it as
//: a shell glob pattern and checks for a match against the
//: pathname relative to the location of the `.gitignore` file
//: (relative to the toplevel of the work tree if not from a
//: `.gitignore` file).
// case 2
//: Otherwise, Git treats the pattern as a shell glob suitable
//: for consumption by fnmatch(3) with the FNM_PATHNAME flag:
//: wildcards in the pattern will not match a / in the pathname.
//: For example, "Documentation/{asterisk}.html" matches
//: "Documentation/git.html" but not "Documentation/ppc/ppc.html"
//: or "tools/perf/Documentation/perf.html".
// case 3
//: Two consecutive asterisks ("`**`") in patterns matched against
//: full pathname may have special meaning:
//:
//: - A leading "`**`" followed by a slash means match in all
//: directories. For example, "`**/foo`" matches file or directory
//: "`foo`" anywhere, the same as pattern "`foo`". "`**/foo/bar`"
//: matches file or directory "`bar`" anywhere that is directly
//: under directory "`foo`".
//:
//: - A trailing "`/**`" matches everything inside. For example,
//: "`abc/**`" matches all files inside directory "`abc`", relative
//: to the location of the `.gitignore` file, with infinite depth.
//:
//: - A slash followed by two consecutive asterisks then a slash
//: matches zero or more directories. For example, "`a/**/b`"
//: matches "`a/b`", "`a/x/b`", "`a/x/y/b`" and so on.
//:
//: - Other consecutive asterisks are considered invalid.
rule = new FileRule(result, definition);
}
}
} catch (ParserException e) {
return new InvalidRule(null, definition, e.getMessage());
}
return rule;
}
}
package com.ibizlab.codegen.lite;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ibizlab.codegen.utils.DataObject;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonIgnoreProperties(value = "handler")
public class DstSystemModel {
/**
* 系统标识
*/
@JSONField(name = "pssystemid")
@JsonProperty("pssystemid")
private String pssystemid;
/**
* 系统名称
*/
@JSONField(name = "pssystemname")
@JsonProperty("pssystemname")
private String pssystemname;
/**
* 结构
*/
@JSONField(name = "sysstructure")
@JsonProperty("sysstructure")
private Map sysstructure;
/**
* 应用
*/
@JSONField(name = "apps")
@JsonProperty("apps")
private List<App> apps;
public DstSystemModel addApp(App app)
{
if(apps==null)
apps=new ArrayList<>();
apps.add(app.setSystemid(this.pssystemid));
return this;
}
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonIgnoreProperties(ignoreUnknown = true)
public static class App{
private String id;
private String label;
private String systemid;
private String fullname;
private String type;
private String group;
private String icon;
private Integer visabled;
private String addr;
}
/**
* 校验
*/
@JSONField(name = "md5check")
@JsonProperty("md5check")
private String md5check;
/**
* 排序
*/
@JSONField(name = "showorder")
@JsonProperty("showorder")
private Integer showorder;
private Map<String, Object> extensionparams;
public DstSystemModel setDynamicModelPath(String dynamic_model_path)
{
if(extensionparams==null)
extensionparams=new HashMap<String, Object>();
extensionparams.put("dynamic_model_path",dynamic_model_path);
return this;
}
@JSONField(serialize = false)
@JsonIgnore
public String getDynamicModelPath()
{
if(extensionparams!=null&&extensionparams.get("dynamic_model_path")!=null)
return extensionparams.get("dynamic_model_path").toString();
return null;
}
public DstSystemModel setLastModify(Long lastModify)
{
if(extensionparams==null)
extensionparams=new HashMap<String, Object>();
extensionparams.put("last_modify",lastModify);
return this;
}
@JSONField(serialize = false)
@JsonIgnore
public Long getLastModify()
{
if(extensionparams!=null&&extensionparams.get("last_modify")!=null)
return DataObject.getLongValue(extensionparams.get("last_modify"),0L);
return 0L;
}
public DstSystemModel fromPath(Path path)
{
try {
if(!Files.exists(path))
throw new IllegalArgumentException("读取文件失败DstSystem:"+path.toString());
JSONObject jo= JSON.parseObject(new String(Files.readAllBytes(path), StandardCharsets.UTF_8));
this.setPssystemid(jo.getString("codeName"));
this.setPssystemname(jo.getString("logicName"));
this.setLastModify(path.toFile().lastModified());
if(jo.containsKey("getAllPSApps"))
{
JSONArray array=jo.getJSONArray("getAllPSApps");
array.forEach(obj->{
JSONObject app=(JSONObject)obj;
String appPath=app.getString("path");
if(!StringUtils.isEmpty(appPath))
{
String[] args=appPath.split("/");
if(args.length==3)
{
String appId=args[1];
this.addApp(new App().setId(appId).setLabel(appId));
}
}
});
}
this.setDynamicModelPath(path.getParent().toAbsolutePath().toString());
} catch (IOException e) {
throw new IllegalArgumentException("读取文件失败DstSystem:"+path.toString());
}
return this;
}
}
package com.ibizlab.codegen.lite;
import com.alibaba.fastjson.JSON;
import com.ibizlab.codegen.utils.Inflector;
import net.ibizsys.model.IPSSystem;
import net.ibizsys.model.PSModelServiceImpl;
import net.ibizsys.model.database.IPSDEFDTColumn;
import net.ibizsys.model.dataentity.IPSDataEntity;
import net.ibizsys.model.dataentity.defield.IPSDEField;
import net.ibizsys.model.dataentity.defield.IPSLinkDEField;
import net.ibizsys.model.dataentity.der.IPSDER1N;
import net.ibizsys.model.dataentity.der.IPSDERBase;
import net.ibizsys.model.dataentity.ds.IPSDEDataQueryCode;
import net.ibizsys.model.dataentity.ds.IPSDEDataQueryCodeCond;
import net.ibizsys.model.dataentity.ds.IPSDEDataSetGroupParam;
import net.ibizsys.model.dataentity.ds.PSDEDataSetGroupParamImpl;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DynamicModelStorage {
private static DynamicModelStorage instance=null;
public static DynamicModelStorage getInstance()
{
if(instance==null)
instance=new DynamicModelStorage();
return instance;
}
private String modelPath;
public String getModelPath()
{
return modelPath;
}
public DynamicModelStorage modelPath(String modelPath)
{
this.modelPath=modelPath;
return this;
}
private IPSSystem iPSSystem = null;
private IPSSystem getPSSystem()
{
if(iPSSystem==null)
{
String strPSModelFolderPath=null;
if(Files.exists(Paths.get(getModelPath(),"PSSYSTEM.json"))) {
strPSModelFolderPath= Paths.get(getModelPath()).toString();
}
else if(Files.exists(Paths.get(getModelPath(),"model","PSSYSTEM.json"))) {
strPSModelFolderPath= Paths.get(getModelPath(),"model").toString();
}
else
{
DstSystemModel dynamicModel=getDstSystemModel();
if(dynamicModel!=null)
strPSModelFolderPath = dynamicModel.getDynamicModelPath();
}
Assert.hasLength(strPSModelFolderPath,"加载系统模型错误,未找到对应模型目录");
PSModelServiceImpl psModelService = new PSModelServiceImpl();
psModelService.setPSModelFolderPath(strPSModelFolderPath);
try {
iPSSystem = psModelService.getPSSystem();
Assert.notNull(iPSSystem,"加载系统模型错误:"+strPSModelFolderPath);
} catch (Exception e) {
throw new RuntimeException("加载系统模型错误"+strPSModelFolderPath,e);
}
}
return iPSSystem;
}
private DstSystemModel dstSystemModel=null;
public DstSystemModel getDstSystemModel()
{
if(dstSystemModel==null)
{
dstSystemModel=loopModelDir(new File(getModelPath()));
}
return dstSystemModel;
}
private DstSystemModel loopModelDir(File dir)
{
if(dir.isDirectory())
{
Path path= Paths.get(dir.getAbsolutePath(),"PSSYSTEM.json");
File check=path.toFile();
if(check.exists())
{
DstSystemModel dstSystemModel=new DstSystemModel().fromPath(path);
if(dstSystemModel!=null&&(!StringUtils.isEmpty(dstSystemModel.getPssystemid())))
{
String system=dstSystemModel.getPssystemid();
return dstSystemModel;
}
}
else
{
for(File sub:dir.listFiles())
{
DstSystemModel dstSystemModel=loopModelDir(sub);
if(dstSystemModel!=null)
return dstSystemModel;
}
}
}
return null;
}
private Map<String,MetaEntityModel> entities=null;
public Map<String,MetaEntityModel> getEntities() throws Exception
{
if(entities==null)
{
entities=new HashMap<>();
IPSSystem iPSSystem=getPSSystem();
int i=1;
for(IPSDataEntity dataEntity:iPSSystem.getAllPSDataEntities()){
MetaEntityModel metaEntityModel=new MetaEntityModel();
metaEntityModel.setEntityId(dataEntity.getId()).setEntityName(dataEntity.getName())
.setLogicName(dataEntity.getLogicName()).setCodeName(dataEntity.getCodeName()).setTableName(dataEntity.getTableName())
.setDsId(iPSSystem.getCodeName()+"-"+((StringUtils.isEmpty(dataEntity.getDSLink())||dataEntity.getDSLink().equalsIgnoreCase("DEFAULT"))?"master":dataEntity.getDSLink()))
.setDsName(metaEntityModel.getDsId())
.setSystemId(iPSSystem.getCodeName()).setSystemName(iPSSystem.getLogicName()).setShowOrder(i);
i++;
entities.put(metaEntityModel.getCodeName(),metaEntityModel);
if(!metaEntityModel.getCodeName().toLowerCase().equals(metaEntityModel.getCodeName()))
entities.put(metaEntityModel.getCodeName().toLowerCase(),metaEntityModel);
if(!entities.containsKey(metaEntityModel.getEntityName())) {
entities.put(metaEntityModel.getEntityName(), metaEntityModel);
}
if(!entities.containsKey(metaEntityModel.getEntityName().toLowerCase())) {
entities.put(metaEntityModel.getEntityName().toLowerCase(), metaEntityModel);
}
String pluralize= Inflector.getInstance().pluralize(metaEntityModel.getCodeName()).toLowerCase();
if(!entities.containsKey(pluralize)) {
entities.put(pluralize, metaEntityModel);
}
}
}
return entities;
}
public EntityModel getDynamicEntity(String entity) throws Exception
{
MetaEntityModel metaEntityModel=getEntities().get(entity);
Assert.notNull(metaEntityModel,"未找到对应的实体模型:"+entity);
IPSSystem iPSSystem=getPSSystem();
IPSDataEntity dataEntity = iPSSystem.getPSDataEntity(metaEntityModel.getEntityId(),true);
Assert.notNull(dataEntity,"未找到对应的实体模型:"+entity);
EntityModel entityModel=new EntityModel();
if(dataEntity.isLogicValid())
{
List<Setting> settingList=new ArrayList<>();
String val=dataEntity.getValidLogicValue();
if(StringUtils.isEmpty(val))val="1";
String deVal=dataEntity.getInvalidLogicValue();
if(StringUtils.isEmpty(deVal))deVal="0";
settingList.add(new Setting().setProperty("logicval").setValue(val));
settingList.add(new Setting().setProperty("logicdelval").setValue(deVal));
metaEntityModel.setExtParams(JSON.toJSONString(settingList));
}
entityModel.setEntity(metaEntityModel);
List<String> dsTypes=new ArrayList<>();
if(dataEntity.getAllPSDEDBConfigs()!=null)
{
dataEntity.getAllPSDEDBConfigs().forEach(item->{
dsTypes.add(item.getDBType().toLowerCase().replace("mysql5","mysql"));
if(!entityModel.getTableName().equalsIgnoreCase(item.getTableName()))
entityModel.getEntity().set("table-"+item.getDBType().toLowerCase().replace("mysql5","mysql"),item.getTableName());
});
}
if(dsTypes.size()>0)
entityModel.getEntity().set("ds_types", String.join(",",dsTypes));
Map<String,FieldModel> fieldMaps=new LinkedHashMap<>();
for(IPSDEField defield:dataEntity.getAllPSDEFields())
{
String dict=null;
try { dict=defield.getPSCodeList()!=null?defield.getPSCodeList().getCodeName():null; } catch (Exception ex){}
FieldModel fieldModel=new FieldModel();
MetaFieldModel metaFieldModel=new MetaFieldModel();
metaFieldModel.setFieldId(defield.getId()).setFieldName(defield.getName()).setCodeName(defield.getCodeName()).setFieldLogicName(defield.getLogicName())
.setEntityId(dataEntity.getId()).setEntityCodeName(dataEntity.getCodeName()).setEntityName(dataEntity.getName()).setSystemId(metaEntityModel.getSystemId())
.setFieldUniName(dataEntity.getName()+"."+defield.getName()).setFieldShowName(String.format("%1$s-%2$s[%3$s]",defield.getName(),defield.getLogicName(),dataEntity.getName()))
.setKeyField(defield.isKeyDEField()?1:null).setMajorField(defield.isMajorDEField()?1:null).setUnionKey(defield.getUnionKeyValue()).setFieldType(defield.getDataType())
.setPredefined(defield.getPredefinedType()).setDict(dict).setNullable(defield.isAllowEmpty()?1:0)
.setPhysicalField(defield.isPhisicalDEField()?1:0).setDataType(DataType.findTypeName(defield.getStdDataType())).setDataLength(defield.getLength()).setDataPreci(defield.getPrecision())
.setIsEnableAudit(defield.isEnableAudit()?1:null).setShowOrder(defield.getImportOrder());
if(defield.getAllPSDEFDTColumns()!=null)
{
defield.getAllPSDEFDTColumns().forEach(col->{
if(!metaFieldModel.getFieldName().equalsIgnoreCase(col.getColumnName()))
metaFieldModel.set("column-"+col.getDBType().toLowerCase().replace("mysql5","mysql"),col.getColumnName());
if(StringUtils.isEmpty(metaFieldModel)&&defield.isFormulaDEField()&&(!StringUtils.isEmpty(col.getQueryCodeExp())))
metaFieldModel.setExpression(col.getQueryCodeExp().replace("`","").replace("[","").replace("]",""));
});
}
if(defield.isLinkDEField() && defield instanceof IPSLinkDEField)
{
IPSLinkDEField linkDEField = (IPSLinkDEField)defield;
String relfieldname=linkDEField.getObjectNode().get("getRelatedPSDEField").get("name").asText();
String relfieldcodename=linkDEField.getObjectNode().get("getRelatedPSDEField").get("codeName").asText();
linkDEField.getRelatedPSDEField();
metaFieldModel.setRefFieldId(relfieldcodename)
.setRefFieldName(relfieldname).setRelationId(linkDEField.getPSDER().getId())
.setRelationName(linkDEField.getPSDER().getName()).setRelationCodeName(linkDEField.getPSDER().getCodeName()).setRefEntityName(linkDEField.getPSDER().getMajorPSDataEntity().getName())
.setRefFieldCodeName(relfieldcodename);
}
if(!ObjectUtils.isEmpty(defield.getAllPSDEFSearchModes()))
{
List<String> modes=new ArrayList<>();
defield.getAllPSDEFSearchModes().forEach(item->modes.add(item.getValueOP().toLowerCase()));
if(defield.isEnableQuickSearch())
modes.add("query");
metaFieldModel.set("search_modes", String.join(",",modes));
}
if((!StringUtils.isEmpty(defield.getDefaultValueType()))||(!StringUtils.isEmpty(defield.getDefaultValue())))
{
String defaultValue="";
if(StringUtils.isEmpty(defield.getDefaultValueType())||"NONE".equalsIgnoreCase(defield.getDefaultValueType()))
{
defaultValue=defield.getDefaultValue();
}
else if(!StringUtils.isEmpty(defield.getDefaultValue()))
{
defaultValue= String.format("${%1$s.%2$s}",defield.getDefaultValueType(),defield.getDefaultValue());
}
else
{
defaultValue= String.format("${%1$s}",defield.getDefaultValueType());
}
metaFieldModel.set("default_value",defaultValue);
}
fieldModel.setCodeName(metaFieldModel.getCodeName()).setColumnName(metaFieldModel.getFieldName()).setUnionName(metaFieldModel.getFieldUniName()).setShowName(metaFieldModel.getFieldShowName())
.setComment(metaFieldModel.getFieldLogicName()).setField(metaFieldModel);
fieldMaps.put(fieldModel.getColumnName(),fieldModel);
entityModel.addField(fieldModel);
}
if(dataEntity.getMinorPSDERs()!=null)
{
for(IPSDERBase der : dataEntity.getMinorPSDERs())
{
RelationshipModel rel=new RelationshipModel();
rel.setCodeName(der.getCodeName()).setEntityId(der.getMajorPSDataEntity().getId())
.setEntityCodeName(der.getMajorPSDataEntity().getCodeName()).setEntityName(der.getMajorPSDataEntity().getName())
.setEntityLogicName(der.getMajorPSDataEntity().getLogicName()).setSystemId(iPSSystem.getCodeName()).setTableName(der.getMajorPSDataEntity().getTableName());
MetaRelationshipModel metaRel=new MetaRelationshipModel();
metaRel.setId(der.getId()).setName(der.getName()).setRelationType(der.getDERType()).setCodeName(der.getCodeName()).setRefEntityId(der.getMajorPSDataEntity().getId())
.setRefEntityName(der.getMajorPSDataEntity().getName()).setRefEntityCodeName(der.getMajorPSDataEntity().getCodeName())
.setEntityId(dataEntity.getId()).setEntityName(dataEntity.getName()).setEntityCodeName(dataEntity.getCodeName()).setNestedName(der.getMinorCodeName())
.setSystemId(iPSSystem.getCodeName());
if(der instanceof IPSDER1N)
{
IPSDER1N der1n=(IPSDER1N)der;
String relfieldname=der1n.getPSPickupDEField().getObjectNode().get("getRelatedPSDEField").get("name").asText();
MetaLookupModel lookupModel=new MetaLookupModel().setRelationid(der.getId())
.setFieldname(der1n.getPickupDEFName()).setReffieldname(relfieldname);
metaRel.addLookup(lookupModel);
}
rel.setRelation(metaRel);
entityModel.addReference(rel);
}
}
if(dataEntity.getMajorPSDERs()!=null)
{
for(IPSDERBase der : dataEntity.getMajorPSDERs())
{
if(StringUtils.isEmpty(der.getMinorCodeName()))
continue;
RelationshipModel rel=new RelationshipModel();
rel.setCodeName(der.getMinorCodeName()).setEntityId(der.getMinorPSDataEntity().getId())
.setEntityCodeName(der.getMinorPSDataEntity().getCodeName()).setEntityName(der.getMinorPSDataEntity().getName())
.setEntityLogicName(der.getMinorPSDataEntity().getLogicName()).setSystemId(iPSSystem.getCodeName()).setTableName(der.getMinorPSDataEntity().getTableName());
MetaRelationshipModel metaRel=new MetaRelationshipModel();
metaRel.setId(der.getId()).setName(der.getName()).setRelationType(der.getDERType()).setCodeName(der.getCodeName()).setRefEntityId(der.getMajorPSDataEntity().getId())
.setRefEntityName(der.getMajorPSDataEntity().getName()).setRefEntityCodeName(der.getMajorPSDataEntity().getCodeName())
.setEntityId(dataEntity.getId()).setEntityName(dataEntity.getName()).setEntityCodeName(dataEntity.getCodeName()).setNestedName(der.getMinorCodeName())
.setSystemId(iPSSystem.getCodeName());
if(der instanceof IPSDER1N)
{
IPSDER1N der1n=(IPSDER1N)der;
String relfieldname=der1n.getPSPickupDEField().getObjectNode().get("getRelatedPSDEField").get("name").asText();
MetaLookupModel lookupModel=new MetaLookupModel().setRelationid(der.getId())
.setFieldname(der1n.getPickupDEFName()).setReffieldname(relfieldname);
metaRel.addLookup(lookupModel);
}
rel.setRelation(metaRel);
entityModel.addNested(rel);
}
}
if(dataEntity.getAllPSDEDataQueries()!=null)
{
dataEntity.getAllPSDEDataQueries().forEach(dataQuery->{
try {
if(dataQuery.getAllPSDEDataQueryCodes()!=null)
{
dataQuery.getAllPSDEDataQueryCodes().forEach(dq->{
String code=getQueryCode(dq);
MetaDataSetModel dsModel=new MetaDataSetModel().setDatasetId(entityModel.getEntityName().toLowerCase()+"-dq-"+dataQuery.getCodeName()+"-"+dq.getDBType().toLowerCase().replace("mysql5","mysql"))
.setDatasetName(dataQuery.getLogicName()).setCodeName(dataQuery.getCodeName())
.setEntityId(entityModel.getEntityId()).setEntityName(entityModel.getEntityName()).setDsCode(code);
entityModel.addDataSet(dsModel);
});
}
} catch (Exception exception) {
}
});
}
if(dataEntity.getAllPSDEDataSets()!=null)
{
dataEntity.getAllPSDEDataSets().forEach(dataSet->{
try {
if(dataSet.getPSDEDataQueries()!=null)
{
Map<String, String> map =new HashMap<>();
dataSet.getPSDEDataQueries().forEach(dataQuery->{
try {
if(dataQuery.getAllPSDEDataQueryCodes()!=null)
{
dataQuery.getAllPSDEDataQueryCodes().forEach(dq->{
String code="";
if(!map.containsKey(dq.getDBType())) {
map.put(dq.getDBType(), "");
code="";
}
else {
code = map.get(dq.getDBType());
code = code+"\r\n union all \r\n";
}
code = code+ getQueryCode(dq);
;//"<include refid=\""+entityModel.getEntityName().toLowerCase()+"_dq_"+dataQuery.getCodeName()+"_"+dq.getDBType().toLowerCase()+"\"/>";
map.put(dq.getDBType(),"select t1.* from ("+code+") t1");
});
}
} catch (Exception exception) {
}
});
for(Map.Entry<String, String> entry:map.entrySet())
{
String sql=null;
if(dataSet.getGroupMode()==1||dataSet.getMajorSortPSDEField()!=null)
{
if(dataSet.getGroupMode()==1&&(!ObjectUtils.isEmpty(dataSet.getPSDEDataSetGroupParams())))
{
sql="select ";
int i=0;
for(IPSDEDataSetGroupParam obj:dataSet.getPSDEDataSetGroupParams())
{
if(!(obj instanceof PSDEDataSetGroupParamImpl))
continue;
PSDEDataSetGroupParamImpl groupParam=(PSDEDataSetGroupParamImpl)obj;
if(i>0)sql=sql.concat(",");
if(groupParam.isEnableGroup())
{
if(!StringUtils.isEmpty(groupParam.getGroupCode()))
sql=sql.concat(groupParam.getGroupCode());
else
sql=sql.concat(groupParam.getName());
}
else
sql=sql.concat(groupParam.getGroupCode());
sql=sql.concat(" as ").concat(groupParam.getName().toLowerCase());
i++;
}
sql=sql.concat(" from ( %s ) t1");
}
else
sql="select t1.* from ( %s ) t1";
if(dataSet.getGroupMode()==1&&(!ObjectUtils.isEmpty(dataSet.getPSDEDataSetGroupParams())))
{
sql=sql.concat(" group by ");
int i=0;
for(IPSDEDataSetGroupParam obj:dataSet.getPSDEDataSetGroupParams())
{
if(!(obj instanceof PSDEDataSetGroupParamImpl))
continue;
PSDEDataSetGroupParamImpl groupParam=(PSDEDataSetGroupParamImpl)obj;
if(groupParam.isEnableGroup())
{
if(i>0)sql=sql.concat(",");
if(!StringUtils.isEmpty(groupParam.getGroupCode()))
sql=sql.concat(groupParam.getGroupCode());
else
sql=sql.concat(groupParam.getName());
i++;
}
}
}
if(dataSet.getMajorSortPSDEField()!=null)
{
IPSDEFDTColumn column = dataSet.getMajorSortPSDEField().getPSDEFDTColumn(entry.getKey().toLowerCase().replace("mysql5","mysql"),false);
sql=sql.concat(" order by ").concat(column==null?dataSet.getMajorSortPSDEField().getName():column.getColumnName());
if(!StringUtils.isEmpty(dataSet.getMajorSortDir()))
sql=sql.concat(" ").concat(dataSet.getMajorSortDir());
if(dataSet.getMinorSortPSDEField()!=null)
{
IPSDEFDTColumn subCol = dataSet.getMinorSortPSDEField().getPSDEFDTColumn(entry.getKey().toLowerCase().replace("mysql5","mysql"),false);
sql=sql.concat(",").concat(subCol==null?dataSet.getMinorSortPSDEField().getName():subCol.getColumnName());
if(!StringUtils.isEmpty(dataSet.getMinorSortDir()))
sql=sql.concat(" ").concat(dataSet.getMinorSortDir());
}
}
}
MetaDataSetModel dsModel=new MetaDataSetModel().setDatasetId(entityModel.getEntityName().toLowerCase()+"-ds-"+dataSet.getCodeName()+"-"+entry.getKey().toLowerCase().replace("mysql5","mysql"))
.setDatasetName(dataSet.getLogicName()).setCodeName(dataSet.getCodeName())
.setEntityId(entityModel.getEntityId()).setEntityName(entityModel.getEntityName()).setDsCode(entry.getValue().toLowerCase().replace("mysql5","mysql")).setDsModel(sql);
entityModel.addDataSet(dsModel);
}
}
} catch (Exception exception) {
}
});
}
return entityModel;
}
public static enum DataType {
UNKNOWN(0,"UNKNOWN"),
BIGINT(1,"BIGINT"),
BINARY(2,"BINARY"),
BIT(3,"BIT"),
CHAR(4,"CHAR"),
DATETIME(5,"DATETIME"),
DECIMAL(6,"DECIMAL"),
FLOAT(7,"FLOAT"),
IMAGE(8,"IMAGE"),
INT(9,"INT"),
MONEY(10,"MONEY"),
NCHAR(11,"NCHAR"),
NTEXT(12,"NTEXT"),
NVARCHAR(13,"NVARCHAR"),
NUMERIC(14,"NUMERIC"),
REAL(15,"REAL"),
SMALLDATETIME(16,"SMALLDATETIME"),
SMALLINT(17,"SMALLINT"),
SMALLMONEY(18,"SMALLMONEY"),
SQL_VARIANT(19,"SQL_VARIANT"),
SYSNAME(20,"SYSNAME"),
TEXT(21,"TEXT"),
TIMESTAMP(22,"TIMESTAMP"),
TINYINT(23,"TINYINT"),
VARBINARY(24,"VARBINARY"),
VARCHAR(25,"VARCHAR"),
UNIQUEIDENTIFIER(26,"UNIQUEIDENTIFIER"),
DATE(27,"DATE"),
TIME(28,"TIME");
public final int code;
public final String name;
private DataType(int code, String name) {
this.code = code;
this.name = name;
}
public int getCode() {
return code;
}
public String getName() {
return name;
}
public static String findTypeName(Integer type) {
for (DataType userTypeEnum : DataType.values()) {
if (userTypeEnum.getCode()==type) {
return userTypeEnum.getName();
}
}
return VARCHAR.getName();
}
}
private String contextParamConvert(String contextParam)
{
String resultParam=getJavaSqlCode(contextParam).replaceAll("(IN|in) \\(\\$\\{srf(datacontext|sessioncontext|webcontext)\\('(\\w+)','(.*?)'\\)}\\)","$1 (\\${srf.$2.$3})");
resultParam=resultParam.replaceAll("\\$\\{srf(datacontext|sessioncontext|webcontext)\\('(\\w+)','(.*?)'\\)}","#{srf.$1.$2}");
resultParam=resultParam.replaceAll("\\$\\{srf(datacontext|sessioncontext|webcontext)\\('(\\w+)'\\)}","#{srf.$1.$2}");
Pattern p = Pattern.compile("srf.(datacontext|sessioncontext|webcontext).(\\w+)");
Matcher m = p.matcher(resultParam);
StringBuffer sb = new StringBuffer();
while(m.find()){
String match = m.group();
resultParam=resultParam.replace(match,match.toLowerCase());
}
resultParam=resultParam.replace("AND t11.SRFDCID = '__SRFSAASDCID__'","");
return resultParam;
}
private String getQueryCode(IPSDEDataQueryCode dq)
{
String code=contextParamConvert(dq.getQueryCode());
if(dq.getPSDEDataQueryCodeConds()!=null)
{
int i=0;
boolean b=checkIgnoreNullvalueCond(dq.getPSDEDataQueryCodeConds());
for(IPSDEDataQueryCodeCond cond:dq.getPSDEDataQueryCodeConds())
{
if(i==0)
code=code.concat(" where ");
else if(i>0)
code=code.concat(" and ");
code=code.concat(b?checkNullContextParamConvert(cond.getCustomCond()):contextParamConvert(cond.getCustomCond()));
i++;
}
}
return code;
}
private String getJavaSqlCode(String strSQLCode)
{
strSQLCode = strSQLCode.replace("\r\n", " ");
strSQLCode = strSQLCode.replace("\r", " ");
strSQLCode = strSQLCode.replace("\n", " ");
strSQLCode = strSQLCode.replace("\"", "\\\"");
return strSQLCode;
}
private String checkNullContextParamConvert(String contextParam) {
String resultParam = getJavaSqlCode(contextParam).replaceAll("<#assign _value=srf(datacontext|sessioncontext|webcontext)\\('(\\w+)','(.*?)'\\)><#if _value\\?length gt 0>(.*?)\\(\\$\\{_value}\\)<#else>1=1</#if>"," ('${srf.$1.$2}'=null or '${srf.$1.$2}'='' or $4 \\${srf.$1.$2} ");
resultParam = resultParam.replaceAll("<#assign _value=srf(datacontext|sessioncontext|webcontext)\\('(\\w+)','(.*?)'\\)><#if _value\\?length gt 0>(.*?)\\$\\{_value}(.*?)?<#else>1=1</#if>", " (#{srf.$1.$2}=null or #{srf.$1.$2}='' or $4#{srf.$1.$2}$5)");
resultParam=contextParamConvert(resultParam);
return resultParam;
}
private boolean checkIgnoreNullvalueCond(List<IPSDEDataQueryCodeCond> list)
{
if(list!=null)
{
for(IPSDEDataQueryCodeCond cond:list)
{
if(getJavaSqlCode(cond.getCustomCond()).matches("(.*?)srf(datacontext|sessioncontext|webcontext)(.*?)\\\\\"ignoreempty\\\\\":true(.*?)"))
return true;
}
}
return false;
}
private Map<String, Long> systemModifyMap=new HashMap<>();
public void resetSystem()
{
this.entities=null;
this.dstSystemModel=null;
this.iPSSystem=null;
this.entitykeys=null;
}
private Map<String, String> entitykeys = null;
public Map<String, String> getEntitiyIds() throws Exception {
if(entitykeys==null)
{
entitykeys = new HashMap<>();
DstSystemModel dstSystemModel=getDstSystemModel();
if(dstSystemModel!=null)
{
Map<String, MetaEntityModel> entityModels = getEntities();
entityModels.entrySet().forEach(entry->{
String id=entry.getValue().getSystemId().concat(".domain.").concat(entry.getValue().getEntityName());
entitykeys.put(entry.getKey(),id);
});
}
}
return entitykeys;
}
}
package com.ibizlab.codegen.lite;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.ibizlab.codegen.utils.DataObject;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Getter
@Setter
@NoArgsConstructor
@JsonIgnoreProperties(value = "handler")
public class EntityModel {
@JsonIgnore
@JSONField(serialize = false)
public String getEntityId() {
return getEntity().getEntityId();
}
@JsonIgnore
@JSONField(serialize = false)
public String getCodeName() {
return getEntity().getCodeName();
}
@JsonIgnore
@JSONField(serialize = false)
public String getEntityName() {
return getEntity().getEntityName();
}
@JsonIgnore
@JSONField(serialize = false)
public String getTableName() {
return getEntity().getTableName();
}
@JsonIgnore
@JSONField(serialize = false)
public String getLogicName() {
return getEntity().getLogicName();
}
@JsonIgnore
@JSONField(serialize = false)
public String getSystemId() {
return getEntity().getSystemId();
}
private MetaEntityModel entity;
private List<MetaDataSetModel> dataSets;
public EntityModel addDataSet(MetaDataSetModel dataSet)
{
if(dataSets==null)
dataSets=new ArrayList<>();
dataSets.add(dataSet);
return this;
}
private List<FieldModel> fields;
public EntityModel addField(FieldModel fieldModel)
{
if(fields==null)
fields=new ArrayList<>();
fields.add(fieldModel);
return this;
}
private List<RelationshipModel> references;
public EntityModel addReference(RelationshipModel relationshipModel)
{
if(references==null)
references=new ArrayList<>();
references.add(relationshipModel);
return this;
}
@JsonIgnore
@JSONField(serialize = false)
private Map<String,RelationshipModel> refMaps;
@JsonIgnore
@JSONField(serialize = false)
public Map<String,RelationshipModel> getRefMaps()
{
if(refMaps==null)
refMaps=new LinkedHashMap<>();
if(references!=null)
{
references.forEach(ship->{
if(!StringUtils.isEmpty(ship.getCodeName()))
refMaps.put(ship.getCodeName(),ship);
if(!StringUtils.isEmpty(ship.getRelation())) {
String fkname= DataObject.getStringValue(ship.getRelation().getName(),"");
if(!StringUtils.isEmpty(fkname))
refMaps.put(fkname, ship);
}
});
}
return refMaps;
}
private List<RelationshipModel> nesteds;
public EntityModel addNested(RelationshipModel relationshipModel)
{
if(nesteds==null)
nesteds=new ArrayList<>();
nesteds.add(relationshipModel);
return this;
}
@JsonIgnore
@JSONField(serialize = false)
private Map<String, FieldModel> fieldMap = null;
@JsonIgnore
@JSONField(serialize = false)
public Map<String, FieldModel> getFieldMap()
{
if(fields!=null&&fieldMap==null)
{
fieldMap=new LinkedHashMap<>();
fields.forEach(field->{
fieldMap.put(field.getColumnName(),field);
fieldMap.put(field.getCodeName(),field);
});
}
return fieldMap;
}
@JsonIgnore
@JSONField(serialize = false)
private FieldModel lastModifyField;
@JsonIgnore
@JSONField(serialize = false)
public FieldModel getLastModifyField() {
if(fields!=null&&lastModifyField==null)
for(FieldModel fieldModel:fields)
if(fieldModel.isLastModifyField())
{
lastModifyField=fieldModel;
return lastModifyField;
}
return lastModifyField;
}
@JsonIgnore
@JSONField(serialize = false)
private boolean isLogicValid=true;
@JsonIgnore
@JSONField(serialize = false)
public boolean isLogicValid()
{
if(isLogicValid&&logicValidField==null) {
if (fields != null) {
for (FieldModel fieldModel : fields) {
if (fieldModel.isLogicValidField()) {
logicValidField = fieldModel;
return isLogicValid;
}
}
}
isLogicValid = false;
}
return isLogicValid;
}
@JsonIgnore
@JSONField(serialize = false)
private FieldModel logicValidField;
@JsonIgnore
@JSONField(serialize = false)
public FieldModel getLogicValidField() {
if(isLogicValid&&logicValidField==null) {
if (fields != null) {
for (FieldModel fieldModel : fields) {
if (fieldModel.isLogicValidField()) {
logicValidField = fieldModel;
return logicValidField;
}
}
}
isLogicValid = false;
}
return logicValidField;
}
@JsonIgnore
@JSONField(serialize = false)
private String logicVal;
@JsonIgnore
@JSONField(serialize = false)
public String getLogicVal()
{
if(StringUtils.isEmpty(logicVal))
logicVal=this.getExtParams("logicval");
if(StringUtils.isEmpty(logicVal))
logicVal="1";
return logicVal;
}
@JsonIgnore
@JSONField(serialize = false)
private String logicDelVal;
@JsonIgnore
@JSONField(serialize = false)
public String getLogicDelVal()
{
if(StringUtils.isEmpty(logicVal))
logicDelVal=this.getExtParams("logicdelval");
if(StringUtils.isEmpty(logicDelVal))
logicDelVal="0";
return logicDelVal;
}
@JsonIgnore
@JSONField(serialize = false)
private FieldModel keyField;
@JsonIgnore
@JSONField(serialize = false)
public FieldModel getKeyField() {
if(fields!=null&&keyField==null)
for(FieldModel fieldModel:fields)
if(fieldModel.isKeyField()) {
keyField=fieldModel;
return keyField;
}
return keyField;
}
@JsonIgnore
@JSONField(serialize = false)
private List<FieldModel> unionKeyFields;
@JsonIgnore
@JSONField(serialize = false)
public List<FieldModel> getUnionKeyFields() {
if(fields!=null&&unionKeyFields==null) {
unionKeyFields = new ArrayList<>();
for (FieldModel fieldModel : fields)
if (fieldModel.isUnionKeyField())
unionKeyFields.add(fieldModel);
}
return unionKeyFields;
}
@JsonIgnore
@JSONField(serialize = false)
public List<FieldModel> getKeyFields() {
if(this.getKeyField()!=null&&this.getKeyField().isPhysicalField()) {
List<FieldModel> keyFields = new ArrayList<>();
keyFields.add(getKeyField());
return keyFields;
}
else
return getUnionKeyFields();
}
public FieldModel getField(String name)
{
if(StringUtils.isEmpty(name))
return null;
if(fields==null)
return null;
if(getFieldMap()!=null)
return getFieldMap().get(name);
return null;
}
@JsonIgnore
@JSONField(serialize = false)
public String getDefaultQueryScript()
{
if(this.getDataSets()!=null)
{
for(MetaDataSetModel set:this.getDataSets()){
if(StringUtils.isEmpty(set.getDsCode()))
continue;
if("view".equalsIgnoreCase(set.getDatasetId())||
set.getDatasetId().startsWith("dq-view-")||
set.getDatasetId().startsWith(getEntityName().toLowerCase()+"-dq-view-"))
{
return set.getDsCode().replace("`","").replace("[","").replace("]","");
}
}
for(MetaDataSetModel set:this.getDataSets()){
if(StringUtils.isEmpty(set.getDsCode()))
continue;
if("default".equalsIgnoreCase(set.getDatasetId())||
set.getDatasetId().startsWith("dq-default-")||
set.getDatasetId().startsWith(getEntityName().toLowerCase()+"-dq-default-"))
{
return set.getDsCode().replace("`","").replace("[","").replace("]","");
}
}
}
return "";
}
public String getSqlSegment(String dataSet)
{
if("CORE".equalsIgnoreCase(dataSet))
{
String columnSet=this.getKeyField().getColumnExp();
for(FieldModel fieldModel:this.getUnionKeyFields())
{
String columnExp=fieldModel.getColumnExp();
if(StringUtils.isEmpty(columnExp))
continue;
columnSet = columnSet + "," + columnExp;
}
return "select "+columnSet+" from "+this.getTableName()+" ";
}
else if("COUNT".equalsIgnoreCase(dataSet))
{
return "select count(1) from "+this.getTableName()+" ";
}
else if(this.getDataSets()!=null)
{
for(MetaDataSetModel set:this.getDataSets()){
if(StringUtils.isEmpty(set.getDsCode()))
continue;
if(dataSet.equalsIgnoreCase(set.getDatasetId())||
set.getDatasetId().indexOf("ds-"+dataSet.toLowerCase()+"-")>=0||
set.getDatasetId().startsWith(getEntityName().toLowerCase()+"-ds-"+dataSet.toLowerCase()+"-"))
{
return set.getDsCode().replace("`","").replace("[","").replace("]","");
}
}
for(MetaDataSetModel set:this.getDataSets()){
if(StringUtils.isEmpty(set.getDsCode()))
continue;
if(dataSet.equalsIgnoreCase(set.getDatasetId())||
set.getDatasetId().indexOf("dq-"+dataSet.toLowerCase()+"-")>=0||
set.getDatasetId().startsWith(getEntityName().toLowerCase()+"-dq-"+dataSet.toLowerCase()+"-"))
{
return set.getDsCode().replace("`","").replace("[","").replace("]","");
}
}
}
if(dataSet.equalsIgnoreCase("VIEW")||dataSet.equalsIgnoreCase("DEFAULT"))
{
return "";
}
else
{
String columnSet="";
for(FieldModel fieldModel:fields)
{
String columnExp=fieldModel.getColumnExp();
if(StringUtils.isEmpty(columnExp))
continue;
if(!StringUtils.isEmpty(columnSet)){
columnSet=columnSet+",";
}
columnSet=columnSet+columnExp;
}
return "select "+columnSet+" from "+this.getTableName()+" t ";
}
}
@JsonIgnore
@JSONField(serialize = false)
public String getMergeColumnSegment()
{
String sql="";
boolean first=true;
for(FieldModel fieldModel:this.getFields())
{
if(!fieldModel.isPhysicalField())
continue;
if(first)
first=false;
else
sql+=",";
sql+=("#{item."+fieldModel.getColumnName().toUpperCase()+"} "+fieldModel.getColumnName().toUpperCase());
}
return sql;
}
@JsonIgnore
@JSONField(serialize = false)
public String getMergeSegment()
{
String sql="";
sql+= " ON (";
boolean first=true;
for(FieldModel fieldModel:this.getKeyFields())
{
if(!fieldModel.isPhysicalField())
continue;
if(first)
first=false;
else
sql+=" and ";
sql+=("T1."+fieldModel.getColumnName().toUpperCase()+"=T2."+fieldModel.getColumnName().toUpperCase());
}
sql+=")\n" +
" WHEN NOT MATCHED THEN INSERT(";
first=true;
for(FieldModel fieldModel:this.getFields())
{
if(!fieldModel.isPhysicalField())
continue;
if(first)
first=false;
else
sql+=",";
sql+=(fieldModel.getColumnName().toUpperCase());
}
sql+=") VALUES (" ;
first=true;
for(FieldModel fieldModel:this.getFields())
{
if(!fieldModel.isPhysicalField())
continue;
if(first)
first=false;
else
sql+=",";
sql+=("T2."+fieldModel.getColumnName().toUpperCase());
}
sql+=")\n" +
" WHEN MATCHED THEN UPDATE SET " ;
first=true;
for(FieldModel fieldModel:this.getFields())
{
if(!fieldModel.isPhysicalField())
continue;
if(fieldModel.isKeyField())
continue;
if(fieldModel.isUnionKeyField())
continue;
if(first)
first=false;
else
sql+=",";
sql+=("T1."+fieldModel.getColumnName().toUpperCase()+"=T2."+fieldModel.getColumnName().toUpperCase());
}
return sql;
}
@JsonIgnore
@JSONField(serialize = false)
public String getDsName()
{
String dsName=this.getEntity().getDsId();
if(StringUtils.isEmpty(dsName))
{
dsName=this.getSystemId()+"-master";
}
return dsName;
}
public String getExtParams(String key)
{
return DataObject.getStringValue(entity.get(key),"");
}
public String getTableName(String dsType)
{
return DataObject.getStringValue(entity.get("table-"+dsType.toLowerCase()),getTableName());
}
@JsonIgnore
@JSONField(serialize = false)
public List<String> getDsTypes()
{
List<String> dsTypes=new ArrayList<>();
String strDsTypes=DataObject.getStringValue(entity.get("ds_types"),"");
for(String dsType:strDsTypes.split(","))
dsTypes.add(dsType);
return dsTypes;
}
}
package com.ibizlab.codegen.lite;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.ibizlab.codegen.utils.DataObject;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.springframework.util.StringUtils;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonIgnoreProperties(value = "handler")
public class FieldModel {
private String columnName;
private String codeName;
private String unionName;
private String showName;
private String comment;
private MetaFieldModel field;
private RelationshipModel reference;
@JsonIgnore
@JSONField(serialize = false)
public String getColumnExp()
{
if(field.getPhysicalField()!=null && 1==field.getPhysicalField())
{
return columnName+" as \""+columnName.toUpperCase()+"\"";
}
else if(!StringUtils.isEmpty(field.getExpression()))
{
return field.getExpression()+" as \""+columnName.toUpperCase()+"\"";
}
return "";
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isPhysicalField()
{
return this.getField().getPhysicalField()!=null && 1==this.getField().getPhysicalField();
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isKeyField()
{
return this.getField().getKeyField()!=null && 1==this.getField().getKeyField();
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isLogicValidField()
{
return "LOGICVALID".equals(this.getField().getPredefined());
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isLastModifyField()
{
return "UPDATEDATE".equals(this.getField().getPredefined());
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isCreateTimeField()
{
return "CREATEDATE".equals(this.getField().getPredefined());
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isUnionKeyField()
{
return !StringUtils.isEmpty(this.getField().getUnionKey());
}
public String getPropType()
{
String dataType=this.getField().getDataType().toUpperCase();
if( dataType.indexOf("TEXT")>=0||dataType.indexOf("CHAR")>=0||dataType.indexOf("LOB")>=0)
return "string";
else if(dataType.indexOf("TIME")>=0)
return "date-time";
else if(dataType.indexOf("DATE")>=0)
return "date";
else if(dataType.indexOf("NUM")>=0||dataType.indexOf("FLOAT")>=0||dataType.indexOf("DOUBLE")>=0||dataType.indexOf("DECIMAL")>=0)
return "number";
else if(dataType.indexOf("INT")==0)
return "integer";
return "string";
}
public String getColumnName(String dsType)
{
return DataObject.getStringValue(field.get("column-"+dsType.toLowerCase()),getColumnName());
}
}
package com.ibizlab.codegen.lite;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
/**
* 实体[数据集]
*/
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonIgnoreProperties(value = "handler")
@ApiModel("数据集")
public class MetaDataSetModel {
/**
* 标识
*/
@JSONField(name = "dataset_id")
@JsonProperty("dataset_id")
@ApiModelProperty("标识")
private String datasetId;
/**
* 名称
*/
@JSONField(name = "dataset_name")
@JsonProperty("dataset_name")
@ApiModelProperty("名称")
private String datasetName;
/**
* 实体标识
*/
@JSONField(name = "entity_id")
@JsonProperty("entity_id")
@ApiModelProperty("实体标识")
private String entityId;
/**
* 实体
*/
@JSONField(name = "entity_name")
@JsonProperty("entity_name")
@ApiModelProperty("实体")
private String entityName;
/**
* 代码名称
*/
@JSONField(name = "code_name")
@JsonProperty("code_name")
@ApiModelProperty("代码名称")
private String codeName;
/**
* 代码
*/
@JSONField(name = "ds_code")
@JsonProperty("ds_code")
@ApiModelProperty("代码")
private String dsCode;
/**
* 模型
*/
@JSONField(name = "ds_model")
@JsonProperty("ds_model")
@ApiModelProperty("模型")
private String dsModel;
}
package com.ibizlab.codegen.lite;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ibizlab.codegen.utils.DataObject;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 实体[实体]
*/
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonIgnoreProperties(value = "handler")
public class MetaEntityModel{
/**
* 标识
*/
@JSONField(name = "entity_id")
@JsonProperty("entity_id")
private String entityId;
/**
* 实体名
*/
@JSONField(name = "entity_name")
@JsonProperty("entity_name")
private String entityName;
/**
* 逻辑名称
*/
@JSONField(name = "logic_name")
@JsonProperty("logic_name")
private String logicName;
/**
* 代码名称
*/
@JSONField(name = "code_name")
@JsonProperty("code_name")
private String codeName;
/**
* 表名称
*/
@JSONField(name = "table_name")
@JsonProperty("table_name")
private String tableName;
/**
* 系统标识
*/
@JSONField(name = "system_id")
@JsonProperty("system_id")
private String systemId;
/**
* 系统
*/
@JSONField(name = "system_name")
@JsonProperty("system_name")
private String systemName;
/**
* 数据源标识
*/
@JSONField(name = "ds_id")
@JsonProperty("ds_id")
private String dsId;
/**
* 数据源
*/
@JSONField(name = "ds_name")
@JsonProperty("ds_name")
private String dsName;
/**
* 模块标识
*/
@JSONField(name = "module_id")
@JsonProperty("module_id")
private String moduleId;
/**
* 模块
*/
@JSONField(name = "module_name")
@JsonProperty("module_name")
private String moduleName;
/**
* 扩展参数
*/
@JSONField(name = "ext_params")
@JsonProperty("ext_params")
private String extParams;
/**
* 排序
*/
@JSONField(name = "show_order")
@JsonProperty("show_order")
private Integer showOrder;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh", timezone = "GMT+8")
@JSONField(name = "createdate", format = "yyyy-MM-dd HH:mm:ss")
@JsonProperty("createdate")
private Timestamp createdate;
/**
* 最后修改时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh", timezone = "GMT+8")
@JSONField(name = "updatedate", format = "yyyy-MM-dd HH:mm:ss")
@JsonProperty("updatedate")
private Timestamp updatedate;
@JSONField(serialize = false)
@JsonIgnore
private Map<String, Object> extensionparams;
public Object get(String key)
{
if(extensionparams==null)
extensionparams=Setting.getMap(extParams);
return extensionparams.get(key);
}
public MetaEntityModel set(String key, Object value)
{
if(value==null)
return this;
if(extensionparams==null)
extensionparams=Setting.getMap(extParams);
extensionparams.put(key,value);
List<Setting> settingList=new ArrayList<>();
for(Map.Entry<String, Object> entry:extensionparams.entrySet()) {
if(!entry.getKey().equalsIgnoreCase("param"))
settingList.add(new Setting().setProperty(entry.getKey()).setValue(DataObject.getStringValue(entry.getValue(), "")));
}
return setExtParams(JSON.toJSONString(settingList));
}
}
package com.ibizlab.codegen.lite;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ibizlab.codegen.utils.DataObject;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 实体[属性]
*/
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonIgnoreProperties(value = "handler")
@ApiModel("属性")
public class MetaFieldModel {
/**
* 属性标识
*/
@JSONField(name = "field_id")
@JsonProperty("field_id")
@ApiModelProperty("属性标识")
private String fieldId;
/**
* 属性名称
*/
@JSONField(name = "field_name")
@JsonProperty("field_name")
@ApiModelProperty("属性名称")
private String fieldName;
/**
* 代码名称
*/
@JSONField(name = "code_name")
@JsonProperty("code_name")
@ApiModelProperty("代码名称")
private String codeName;
/**
* 实体标识
*/
@JSONField(name = "entity_id")
@JsonProperty("entity_id")
@ApiModelProperty("实体标识")
private String entityId;
/**
* 实体名称
*/
@JSONField(name = "entity_name")
@JsonProperty("entity_name")
@ApiModelProperty("实体名称")
private String entityName;
/**
* 实体代码名称
*/
@JSONField(name = "entity_code_name")
@JsonProperty("entity_code_name")
@ApiModelProperty("实体代码名称")
private String entityCodeName;
/**
* 系统
*/
@JSONField(name = "system_id")
@JsonProperty("system_id")
@ApiModelProperty("系统")
private String systemId;
/**
* 属性逻辑名
*/
@JSONField(name = "field_logic_name")
@JsonProperty("field_logic_name")
@ApiModelProperty("属性逻辑名")
private String fieldLogicName;
/**
* 属性全路径名称
*/
@JSONField(name = "field_uni_name")
@JsonProperty("field_uni_name")
@ApiModelProperty("属性全路径名称")
private String fieldUniName;
/**
* 显示名称
*/
@JSONField(name = "field_show_name")
@JsonProperty("field_show_name")
@ApiModelProperty("显示名称")
private String fieldShowName;
/**
* 引用属性标识
*/
@JSONField(name = "ref_field_id")
@JsonProperty("ref_field_id")
@ApiModelProperty("引用属性标识")
private String refFieldId;
/**
* 引用属性名称
*/
@JSONField(name = "ref_field_name")
@JsonProperty("ref_field_name")
@ApiModelProperty("引用属性名称")
private String refFieldName;
/**
* 引用属性代码名称
*/
@JSONField(name = "ref_field_code_name")
@JsonProperty("ref_field_code_name")
@ApiModelProperty("引用属性代码名称")
private String refFieldCodeName;
/**
* 引用关系标识
*/
@JSONField(name = "relation_id")
@JsonProperty("relation_id")
@ApiModelProperty("引用关系标识")
private String relationId;
/**
* 引用关系
*/
@JSONField(name = "relation_name")
@JsonProperty("relation_name")
@ApiModelProperty("引用关系")
private String relationName;
/**
* 关系代码
*/
@JSONField(name = "relation_code_name")
@JsonProperty("relation_code_name")
@ApiModelProperty("关系代码")
private String relationCodeName;
/**
* 引用实体
*/
@JSONField(name = "ref_entity_name")
@JsonProperty("ref_entity_name")
@ApiModelProperty("引用实体")
private String refEntityName;
/**
* 主键
*/
@JSONField(name = "key_field")
@JsonProperty("key_field")
@ApiModelProperty("主键")
private Integer keyField;
/**
* 主信息
*/
@JSONField(name = "major_field")
@JsonProperty("major_field")
@ApiModelProperty("主信息")
private Integer majorField;
/**
* 联合主键
*/
@JSONField(name = "union_key")
@JsonProperty("union_key")
@ApiModelProperty("联合主键")
private String unionKey;
/**
* 属性类型
*/
@JSONField(name = "field_type")
@JsonProperty("field_type")
@ApiModelProperty("属性类型")
private String fieldType;
/**
* 预定义类型
*/
@JSONField(name = "predefined")
@JsonProperty("predefined")
@ApiModelProperty("预定义类型")
private String predefined;
/**
* 数据字典
*/
@JSONField(name = "dict")
@JsonProperty("dict")
@ApiModelProperty("数据字典")
private String dict;
/**
* 允许为空
*/
@JSONField(name = "nullable")
@JsonProperty("nullable")
@ApiModelProperty("允许为空")
private Integer nullable;
/**
* 物理属性
*/
@JSONField(name = "physical_field")
@JsonProperty("physical_field")
@ApiModelProperty("物理属性")
private Integer physicalField;
/**
* 数据类型
*/
@JSONField(name = "data_type")
@JsonProperty("data_type")
@ApiModelProperty("数据类型")
private String dataType;
/**
* 长度
*/
@JSONField(name = "data_length")
@JsonProperty("data_length")
@ApiModelProperty("长度")
private Integer dataLength;
/**
* 精度
*/
@JSONField(name = "data_preci")
@JsonProperty("data_preci")
@ApiModelProperty("精度")
private Integer dataPreci;
/**
* 逻辑表达式
*/
@JSONField(name = "expression")
@JsonProperty("expression")
@ApiModelProperty("逻辑表达式")
private String expression;
/**
* 扩展属性
*/
@JSONField(name = "extension_field")
@JsonProperty("extension_field")
@ApiModelProperty("扩展属性")
private Integer extensionField;
/**
* 审计
*/
@JSONField(name = "is_enable_audit")
@JsonProperty("is_enable_audit")
@ApiModelProperty("审计")
private Integer isEnableAudit;
/**
* 排序
*/
@JSONField(name = "show_order")
@JsonProperty("show_order")
@ApiModelProperty("排序")
private Integer showOrder;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh", timezone = "GMT+8")
@JSONField(name = "createdate", format = "yyyy-MM-dd HH:mm:ss")
@JsonProperty("createdate")
@ApiModelProperty("创建时间")
private Timestamp createdate;
/**
* 最后修改时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh", timezone = "GMT+8")
@JSONField(name = "updatedate", format = "yyyy-MM-dd HH:mm:ss")
@JsonProperty("updatedate")
@ApiModelProperty("最后修改时间")
private Timestamp updatedate;
/**
* 扩展参数
*/
@JSONField(name = "ext_params")
@JsonProperty("ext_params")
private String extParams;
@JSONField(serialize = false)
@JsonIgnore
private Map<String, Object> extensionparams;
public Object get(String key)
{
if(extensionparams==null)
extensionparams=Setting.getMap(extParams);
return extensionparams.get(key);
}
public MetaFieldModel set(String key, Object value)
{
if(value==null)
return this;
if(extensionparams==null)
extensionparams=Setting.getMap(extParams);
extensionparams.put(key,value);
List<Setting> settingList=new ArrayList<>();
for(Map.Entry<String, Object> entry:extensionparams.entrySet()) {
if(!entry.getKey().equalsIgnoreCase("param"))
settingList.add(new Setting().setProperty(entry.getKey()).setValue(DataObject.getStringValue(entry.getValue(), "")));
}
return setExtParams(JSON.toJSONString(settingList));
}
}
package com.ibizlab.codegen.lite;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* [lookup] 对象
*/
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@ApiModel("lookup")
public class MetaLookupModel implements Serializable {
/**
* 标识
*/
@JSONField(name = "id")
@JsonProperty("id")
@ApiModelProperty("标识")
private String id;
/**
* 关系标识
*/
@JSONField(name = "relationId")
@JsonProperty("relationId")
@ApiModelProperty("关系标识")
private String relationid;
/**
* 属性名称
*/
@JSONField(name = "fieldName")
@JsonProperty("fieldName")
@ApiModelProperty("属性名称")
private String fieldname;
/**
* 引用属性名称
*/
@JSONField(name = "refFieldName")
@JsonProperty("refFieldName")
@ApiModelProperty("引用属性名称")
private String reffieldname;
}
package com.ibizlab.codegen.lite;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
/**
* 实体[实体关系]
*/
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonIgnoreProperties(value = "handler")
@ApiModel("实体关系")
public class MetaRelationshipModel implements Serializable {
/**
* 关系标识
*/
@JSONField(name = "id")
@JsonProperty("id")
@ApiModelProperty("关系标识")
private String id;
/**
* 关系名称
*/
@JSONField(name = "name")
@JsonProperty("name")
@ApiModelProperty("关系名称")
private String name;
/**
* 类型
*/
@JSONField(name = "relation_type")
@JsonProperty("relation_type")
@ApiModelProperty("类型")
private String relationType;
/**
* 代码名称
*/
@JSONField(name = "code_name")
@JsonProperty("code_name")
@ApiModelProperty("代码名称")
private String codeName;
/**
* 实体标识
*/
@JSONField(name = "entity_id")
@JsonProperty("entity_id")
@ApiModelProperty("实体标识")
private String entityId;
/**
* 实体名称
*/
@JSONField(name = "entity_name")
@JsonProperty("entity_name")
@ApiModelProperty("实体名称")
private String entityName;
/**
* 实体代码名称
*/
@JSONField(name = "entity_code_name")
@JsonProperty("entity_code_name")
@ApiModelProperty("实体代码名称")
private String entityCodeName;
/**
* 引用实体标识
*/
@JSONField(name = "ref_entity_id")
@JsonProperty("ref_entity_id")
@ApiModelProperty("引用实体标识")
private String refEntityId;
/**
* 引用实体名称
*/
@JSONField(name = "ref_entity_name")
@JsonProperty("ref_entity_name")
@ApiModelProperty("引用实体名称")
private String refEntityName;
/**
* 引用实体代码名称
*/
@JSONField(name = "ref_entity_code_name")
@JsonProperty("ref_entity_code_name")
@ApiModelProperty("引用实体代码名称")
private String refEntityCodeName;
/**
* 嵌套代码名称
*/
@JSONField(name = "nested_name")
@JsonProperty("nested_name")
@ApiModelProperty("嵌套代码名称")
private String nestedName;
/**
* 系统
*/
@JSONField(name = "system_id")
@JsonProperty("system_id")
@ApiModelProperty("系统")
private String systemId;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh", timezone = "GMT+8")
@JSONField(name = "createdate", format = "yyyy-MM-dd HH:mm:ss")
@JsonProperty("createdate")
@ApiModelProperty("创建时间")
private Timestamp createdate;
/**
* 最后修改时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh", timezone = "GMT+8")
@JSONField(name = "updatedate", format = "yyyy-MM-dd HH:mm:ss")
@JsonProperty("updatedate")
@ApiModelProperty("最后修改时间")
private Timestamp updatedate;
/**
* lookup
*/
@JSONField(name = "lookups")
@JsonProperty("lookups")
private List<MetaLookupModel> lookup;
public MetaRelationshipModel addLookup(MetaLookupModel obj)
{
if(lookup==null)
lookup=new ArrayList<>();
lookup.add(obj);
return this;
}
}
package com.ibizlab.codegen.lite;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonIgnoreProperties(value = "handler")
public class RelationshipModel {
private String codeName;
private String entityName;
private String entityCodeName;
private String entityLogicName;
private String systemId;
private String dataSourceName;
private String tableName;
private String entityId;
private MetaRelationshipModel relation;
}
package com.ibizlab.codegen.lite;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ibizlab.codegen.utils.DataObject;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.io.StringReader;
import java.util.*;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
public class Setting {
private String property;
private String value;
public static String getValue(String configString, String propertyName)
{
return DataObject.getStringValue(getMap(configString).get(propertyName),"");
}
public static Map getMap(String configString)
{
Map map=new HashMap();
map.put("param",configString);
if(!(StringUtils.isEmpty(configString)))
{
try
{
Object obj= JSON.parse(configString);
if(obj==null)
return map;
else if (obj instanceof JSONArray)
{
List<Setting> settings= JSONArray.parseArray(configString,Setting.class);
for(Setting setting:settings)
map.put(setting.getProperty(),setting.getValue());
}
else if (obj instanceof JSONObject)
{
JSONObject jo = (JSONObject)obj;
jo.keySet().forEach(key->{
map.put(key,jo.get(key));
});
}
}
catch (Exception ex)
{
if(configString.indexOf("=")>0)
{
Properties proper = new Properties();
try {
proper.load(new StringReader(configString)); //把字符串转为reader
} catch (IOException e) {
}
Enumeration enum1 = proper.propertyNames();
while (enum1.hasMoreElements()) {
String strKey = (String) enum1.nextElement();
String strValue = proper.getProperty(strKey);
map.put(strKey, strValue);
}
}
}
}
return map;
}
}
package com.ibizlab.codegen.model;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import lombok.experimental.Accessors;
import org.springframework.util.StringUtils;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonIgnoreProperties(ignoreUnknown = true)
public class DOModel implements Serializable {
/**
* 标识
*/
@JSONField(name = "id")
@JsonProperty("id")
@ApiModelProperty("标识")
private String id;
/**
* 名称
*/
@JSONField(name = "name")
@JsonProperty("name")
@ApiModelProperty("名称")
private String name;
/**
* 名称
*/
@JSONField(name = "title")
@JsonProperty("title")
@ApiModelProperty("名称")
private String title;
/**
* 系统
*/
@JSONField(name = "systemId")
@JsonProperty("systemId")
@ApiModelProperty("系统")
private String systemId;
/**
* 包名
*/
@JSONField(name = "packageName")
@JsonProperty("packageName")
@ApiModelProperty("包名")
private String packageName;
/**
* 描述
*/
@JSONField(name = "description")
@JsonProperty("description")
@ApiModelProperty("描述")
private String description;
/**
* 定义
*/
@JSONField(name = "schema")
@JsonProperty("schema")
@ApiModelProperty("定义")
private PojoSchema schema;
/**
* 模型
*/
@JSONField(name = "model")
@JsonProperty("model")
@ApiModelProperty("模型")
private String model;
public void setSchema(PojoSchema schema) {
if(schema!=null)
{
if(StringUtils.isEmpty(schema.getId()))
schema.setId(schema.getSystem()+".domain."+schema.getName());
this.setId(schema.getId());
if(!StringUtils.isEmpty(schema.getName()))
this.setName(schema.getName());
if(!StringUtils.isEmpty(schema.getSystem()))
this.setSystemId(schema.getSystem());
if(!StringUtils.isEmpty(schema.getTitle()))
this.setTitle(schema.getTitle());
if(!StringUtils.isEmpty(schema.getDescription()))
this.setDescription(schema.getDescription());
if(!StringUtils.isEmpty(schema.getPackage()))
this.setPackageName(schema.getPackage());
}
this.schema = schema;
}
@JSONField(serialize = false)
@JsonIgnore
private Map<String,POSchema> poSchemas;
@JSONField(serialize = false)
@JsonIgnore
public POSchema getDefaultPOSchema()
{
return getPOSchema("default");
}
public DOModel addPOSchema(String name, POSchema poSchema)
{
if(poSchema!=null)
{
if(poSchemas==null)
poSchemas=new LinkedHashMap<>();
poSchemas.put(name,poSchema.build());
}
return this;
}
public POSchema getPOSchema(String name)
{
if(StringUtils.isEmpty(name)&&this.getSchema()!=null&&(!StringUtils.isEmpty(this.getSchema().getDefaultDataSoruce())))
name=this.getSchema().getDefaultDataSoruce();
if(StringUtils.isEmpty(name))
name="mysql";
if(poSchemas==null)
poSchemas=new LinkedHashMap<>();
if(poSchemas.containsKey(name))
{
return poSchemas.get(name);
}
String vendorProvider=POSchema.provider.get(name.toLowerCase());
if((!StringUtils.isEmpty(vendorProvider))&&(!name.equalsIgnoreCase(vendorProvider))&&poSchemas.containsKey(vendorProvider))
return poSchemas.get(vendorProvider);
if(this.getSchema()!=null&&("mongodb".equals(name)))
{
POSchema documentPOSchema= TransUtils.PojoSchema2DocumentPO(this.getSchema());
if(documentPOSchema!=null) {
poSchemas.put(name, documentPOSchema);
return documentPOSchema;
}
}
if(this.getSchema()!=null&&("default".equals(name)||this.getSchema().getDefaultDataSoruce().equalsIgnoreCase(name)))
{
POSchema defaultPOSchema= TransUtils.PojoSchema2PO(this.getSchema());
if(defaultPOSchema!=null) {
poSchemas.put("default", defaultPOSchema);
if(!StringUtils.isEmpty(this.getSchema().getDefaultDataSoruce()))
poSchemas.put(this.getSchema().getDefaultDataSoruce().toLowerCase(),defaultPOSchema);
return defaultPOSchema;
}
}
return null;
}
}
package com.ibizlab.codegen.model;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.springframework.util.StringUtils;
import java.util.Set;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonIgnoreProperties(ignoreUnknown = true)
public class DSLink
{
private String name;
private String description;
private String type;
private String driverClassName;
private String url;
private String username;
private String password;
private String schema;
private Set<String> usings;
@JSONField(serialize = false)
@JsonIgnore
public boolean isMongodb()
{
return "mongodb".equalsIgnoreCase(this.getType())||(this.getUrl()!=null&&this.getUrl().startsWith("mongodb"));
}
@JSONField(serialize = false)
@JsonIgnore
public boolean isDatabase()
{
return (!StringUtils.isEmpty(this.getDriverClassName()))&&(!StringUtils.isEmpty(this.getUrl()));
}
@JSONField(serialize = false)
@JsonIgnore
public boolean isElasticSearch()
{
return "elasticsearch".equalsIgnoreCase(this.getType())||"es".equalsIgnoreCase(this.getType());
}
@JSONField(serialize = false)
@JsonIgnore
public boolean isCassandra()
{
return "cassandra".equalsIgnoreCase(this.getType());
}
@JSONField(serialize = false)
@JsonIgnore
public Object source;
public DSLink setSource(Object source)
{
this.source=source;
return this;
}
private static DSLink defaultLink;
public static DSLink getDefaultLink()
{
if(defaultLink==null)
defaultLink=new DSLink().setName("master").setType("mysql");
return defaultLink;
}
}
package com.ibizlab.codegen.model;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ibizlab.codegen.utils.DataObject;
import org.springframework.util.ObjectUtils;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;
public class DataObj<K,V> extends HashMap<K,V> {
public <T> T set(String key, V value)
{
this.put((K)key,value);
return (T)this;
}
@Override
public V get(Object key) {
if(key==null)
return null;
V objValue=super.get(key);
if(objValue==null)
objValue=super.get(key.toString().toUpperCase());
if(objValue==null)
objValue=super.get(key.toString().toLowerCase());
return objValue;
}
public JSONObject getJSONObjectValue(String strParamName) {
return getJSONObjectValue(strParamName,new JSONObject());
}
public JSONObject getJSONObjectValue(String strParamName, JSONObject jDefault) {
return DataObject.getJSONObjectValue(this.get(strParamName),jDefault);
}
public <T> List<T> getListValue(String strParamName,Class<T> clazz)
{
List<T> list= new ArrayList<>();
Object val=this.get(strParamName);
if(val != null && val instanceof List)
{
list=JSONArray.parseArray(JSON.toJSONString(val),clazz);
}
return list;
}
public List<String> getListValue( String strParamName) {
return DataObject.getListValue(strParamName);
}
public JSONArray getJSONArrayValue( String strParamName) {
return getJSONArrayValue(strParamName,new JSONArray());
}
public JSONArray getJSONArrayValue( String strParamName, JSONArray jDefault) {
return DataObject.getJSONArrayValue(this.get(strParamName),jDefault);
}
public Integer getIntegerValue(String objValue) {
return getIntegerValue(objValue, Integer.MIN_VALUE);
}
public Integer getIntegerValue( String strParamName, Integer nDefault) {
return DataObject.getIntegerValue(this.get(strParamName),nDefault);
}
public Float getFloatValue(String objValue) {
return this.getFloatValue(objValue,-9999f);
}
public Float getFloatValue( String strParamName, float fDefault) {
return DataObject.getFloatValue(this.get(strParamName),fDefault);
}
public BigDecimal getBigDecimalValue(String objValue) {
return this.getBigDecimalValue(objValue,BigDecimal.valueOf(-9999));
}
public BigDecimal getBigDecimalValue( String strParamName, BigDecimal fDefault) {
return DataObject.getBigDecimalValue(this.get(strParamName),fDefault);
}
public Long getLongValue( String strParamName) {
return this.getLongValue(strParamName,Long.MIN_VALUE);
}
public Long getLongValue( String strParamName, long nDefault) {
return DataObject.getLongValue(this.get(strParamName),nDefault);
}
public String getStringValue(String objValue) {
return getStringValue(objValue, "");
}
public String getStringValue( String strParamName, String strDefault) {
return DataObject.getStringValue(this.get(strParamName),strDefault);
}
public byte[] getBinaryValue(String objValue) {
return getBinaryValue(objValue, null);
}
public byte[] getBinaryValue(String strParamName, byte[] def) {
return DataObject.getBinaryValue(this.get(strParamName),def);
}
public Boolean getBooleanValue(String strParamName)
{
return getBooleanValue(strParamName,false);
}
public Boolean getBooleanValue(String strParamName,Boolean bDefault)
{
return DataObject.getBooleanValue(this.get(strParamName),bDefault);
}
public Timestamp getTimestampBegin( String strParamName) {
return getTimestampValue(strParamName, DataObject.getBeginDate());
}
public Timestamp getTimestampEnd( String strParamName) {
Object objValue = this.get(strParamName);
if (objValue == null) {
return DataObject.getEndDate();
}
try {
Timestamp t= DataObject.getTimestampValue(objValue, DataObject.getEndDate());
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String time = df.format(t);
Calendar cl=Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
cl.setTime(Timestamp.valueOf(time+" 23:59:59"));
return new Timestamp(cl.getTime().getTime());
} catch (Exception ex) {
return DataObject.getEndDate();
}
}
public Timestamp getTimestampValue( String strParamName, Timestamp dtDefault) {
Object objValue = this.get(strParamName);
if (objValue == null || objValue.equals("")) {
return dtDefault;
}
try {
return DataObject.getTimestampValue(objValue,null);
} catch (Exception ex) {
return dtDefault;
}
}
public <T> T copyTo(T targetEntity, boolean bIncEmpty){
if(targetEntity instanceof DataObj){
for(K field : this.keySet()){
Object value=this.get(field);
if( !ObjectUtils.isEmpty(value) || ObjectUtils.isEmpty(value) && bIncEmpty ){
((DataObj) targetEntity).set((String)field,value);
}
}
}
else if(targetEntity instanceof Map){
for(K field : this.keySet()){
Object value=this.get(field);
if( !ObjectUtils.isEmpty(value) || ObjectUtils.isEmpty(value) && bIncEmpty ){
((Map) targetEntity).put(field,value);
}
}
}
return targetEntity;
}
}
package com.ibizlab.codegen.model;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.ibizlab.codegen.lite.DynamicModelStorage;
import com.ibizlab.codegen.lite.EntityModel;
import org.springframework.util.Assert;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
public class ModelStorage {
public static String USER_HOME = Paths.get(System.getProperty("user.home"),".ibizlab").toString();
private DynamicModelStorage dynamicService=DynamicModelStorage.getInstance().modelPath(this.getModelPath());
private String system=dynamicService.getDstSystemModel().getPssystemid();
public String getModelPath()
{
if(modelPath.equals(File.separator))
return modelPath.substring(0,modelPath.length()-1);
return modelPath;
}
public DOModel loadDOModel(String entity)
{
EntityModel entityModel= null;
try {
entityModel = dynamicService.getDynamicEntity(entity);
} catch (Exception exception) {
exception.printStackTrace();
}
Assert.notNull(entityModel,"loadDOModel未找到实体"+"."+entity);
PojoSchema schema = TransUtils.EntityModelModel2Schema(entityModel);
Assert.notNull(schema,"loadDOModel未找到实体"+"."+entity);
DOModel doModel=new DOModel();
doModel.setSchema(schema);
for (String dsType : entityModel.getDsTypes()) {
POSchema poSchema = TransUtils.EntityModelModel2PO(entityModel, dsType);
if (poSchema != null) {
doModel.addPOSchema(dsType, poSchema);
}
}
return doModel;
}
public DOModel getDOModel(String entity)
{
DOModel doModel=null;
PojoSchema schema=null;
Path storePath = Paths.get(ModelStorage.USER_HOME,system,"repo",entity,"domain",entity+".json");
if(!Files.exists(storePath))
{
try {
String entityTag=dynamicService.getEntitiyIds().get(entity);
Assert.hasLength(entityTag,"获取模型失败"+entity);
if(!entityTag.endsWith("."+entity))
{
String[] args=entityTag.split("[.]");
entity=args[2];
storePath = Paths.get(ModelStorage.USER_HOME,system,"repo",entity,"domain",entity+".json");
}
} catch (Exception exception) {
throw new RuntimeException("获取模型失败"+entity,exception);
}
}
File json= storePath.toFile();
if((json.exists()&&json.lastModified()<dynamicService.getDstSystemModel().getLastModify())||(!json.exists()))
{
doModel = loadDOModel(entity);
schema = doModel.getSchema();
if(schema!=null)
{
if(doModel.getPoSchemas()!=null)
{
Path poPath = Paths.get(ModelStorage.USER_HOME,system,"repo",doModel.getName(),"repository",doModel.getName()+".json");
try {
File dir=poPath.getParent().toFile();
if(!dir.exists())
dir.mkdirs();
Files.write(poPath, JSON.toJSONBytes(doModel.getPoSchemas()));
} catch (Exception e) {
throw new RuntimeException("保存文件失败POSchemas:"+poPath.toString());
}
}
schema.writeTo(Paths.get(ModelStorage.USER_HOME,system,"repo",doModel.getName(),"domain",doModel.getName()+".json"));
}
}
else {
doModel = new DOModel();
schema = PojoSchema.fromPath(storePath);
if(schema!=null) {
doModel.setSchema(schema);
Path poPath = Paths.get(ModelStorage.USER_HOME, system,"repo", entity, "repository", entity + ".json");
if (Files.exists(poPath)) {
try {
doModel.setPoSchemas(JSON.parseObject(new String(Files.readAllBytes(poPath), StandardCharsets.UTF_8), new TypeReference<LinkedHashMap<String, POSchema>>() {
}));
} catch (IOException e) {
}
}
}
}
Assert.notNull(schema,"未找到对应的模型"+entity);
return doModel;
}
}
package com.ibizlab.codegen.model;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.ibizlab.codegen.utils.DataObject;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonIgnoreProperties(ignoreUnknown = true)
public class POSchema {
@JSONField(ordinal = 1)
private String name;
@JSONField(ordinal = 2)
private String remarks;
@JSONField(ordinal = 3)
private String dsType;
@JSONField(ordinal = 4)
private String defaultDataSource;
@JSONField(ordinal = 5)
private String logicVal;
@JSONField(ordinal = 6)
private String logicDelVal;
public String getLogicVal() {
if(StringUtils.isEmpty(logicVal))
return "1";
return logicVal;
}
public String getLogicDelVal() {
if(StringUtils.isEmpty(logicDelVal))
return "0";
return logicDelVal;
}
@JSONField(ordinal = 7)
private List<Column> columns;
@JSONField(ordinal = 8)
private List<Column> transients;
public POSchema setColumns(List<Column> columns)
{
this.columns=columns;
refreshColumnMaps();
return this;
}
public POSchema setTransients(List<Column> transients)
{
this.transients=transients;
refreshColumnMaps();
return this;
}
public POSchema addColumn(Column column)
{
if(columns==null)
columns=new ArrayList<>();
columns.add(column);
refreshColumn(column);
return this;
}
public POSchema addTransient(Column column)
{
if(transients==null)
transients=new ArrayList<>();
transients.add(column);
refreshColumn(column);
return this;
}
@JSONField(ordinal = 9)
private List<ForeignKeyConstraint> foreignKeyConstraints;
public POSchema addForeignKeyConstraint(ForeignKeyConstraint foreignKeyConstraint)
{
if(foreignKeyConstraints==null)
foreignKeyConstraints=new ArrayList<>();
foreignKeyConstraints.add(foreignKeyConstraint);
return this;
}
@JsonIgnore
@JSONField(serialize = false)
public Set<String> getForeignKey()
{
Set<String> fks=new HashSet<>();
if(foreignKeyConstraints!=null)
{
foreignKeyConstraints.forEach(fk->fks.add(fk.getConstraintName()));
}
return fks;
}
@JsonIgnore
@JSONField(serialize = false)
private Map<String,Column> columnMaps;
@JsonIgnore
@JSONField(serialize = false)
private Map<String, String> baseColumnMap;
@JsonIgnore
@JSONField(serialize = false)
private Map<String, String> resultMap;
@JsonIgnore
@JSONField(serialize = false)
private Map<String, String> keyMap;
@JsonIgnore
@JSONField(serialize = false)
private Column keyColumn;
@JsonIgnore
@JSONField(serialize = false)
public Column getKeyColumn() {
if(keyColumn==null)
{
if((!ObjectUtils.isEmpty(getKeyMap()))&&getKeyMap().size()==1)
keyColumn = this.getColumn(keyMap.values().iterator().next());
}
return keyColumn;
}
@JsonIgnore
@JSONField(serialize = false)
private Map<String,Column> searchMap;
@JsonIgnore
@JSONField(serialize = false)
private Map<String,Column> quickSearch;
@JsonIgnore
@JSONField(serialize = false)
public Map<String, Column> getColumnMaps() {
if(columns!=null&&columnMaps==null)
{
refreshColumnMaps();
}
return columnMaps;
}
@JSONField(ordinal = 10)
public boolean needTrans = false;
public void refreshColumnMaps()
{
columnMaps=new LinkedHashMap<>();
resultMap=new LinkedHashMap<>();
baseColumnMap=new LinkedHashMap<>();
keyMap=new LinkedHashMap<>();
searchMap=new LinkedHashMap<>();
quickSearch=new LinkedHashMap<>();
columns.forEach(column -> {
refreshColumn(column);
});
if(logicValid&&logicValidColumn==null)
logicValid=false;
}
public void refreshColumn(Column column)
{
if(columnMaps==null)
columnMaps=new LinkedHashMap<>();
if(resultMap==null)
resultMap=new LinkedHashMap<>();
if(baseColumnMap==null)
baseColumnMap=new LinkedHashMap<>();
if(keyMap==null)
keyMap=new LinkedHashMap<>();
if(searchMap==null)
searchMap=new LinkedHashMap<>();
if(quickSearch==null)
quickSearch=new LinkedHashMap<>();
columnMaps.put(column.getName().toLowerCase(),column);
if(!ObjectUtils.isEmpty(column.getSearchModes()))
{
column.getSearchModes().forEach(mode->{
if(!mode.equalsIgnoreCase("query"))
searchMap.put("n_"+column.getName().toLowerCase()+"_"+mode,column);
else
quickSearch.put(column.getName().toLowerCase(),column);
});
}
if(!column.isComputed())
{
if(column.isLogicValid()) {
this.setLogicValid(true);
this.setLogicValidColumn(column);
if(StringUtils.isEmpty(column.getDefaultValue()))
column.setDefaultValue(this.getLogicVal());
logicValidCond = " "+column.getName()+"=";
logicValidDelCond = " "+column.getName()+"=";
if(column.isText()) {
logicValidCond += ("'" + this.getLogicVal() + "' ");
logicValidDelCond += ("'" + this.getLogicDelVal() + "' ");
}
else {
logicValidCond += (this.getLogicVal() + " ");
logicValidDelCond += (this.getLogicDelVal() + " ");
}
}
if(column.isTenant())
this.setTenantColumn(column);
if(column.isCreateTime())
this.setCreateTimeColumn(column);
if(column.isLastModify())
this.setLastModifyColumn(column);
}
if((!StringUtils.isEmpty(column.getAlias()))&&(!column.getAlias().equalsIgnoreCase(column.getName())))
{
needTrans=true;
columnMaps.put(column.getAlias().toLowerCase(), column);
resultMap.put(column.getName().toLowerCase(),column.getAlias().toLowerCase());
if(!column.isComputed())
{
baseColumnMap.put(column.getName().toLowerCase(),column.getAlias().toLowerCase());
if(column.isPrimaryKey())
keyMap.put(column.getName().toLowerCase(),column.getAlias().toLowerCase());
}
if(!ObjectUtils.isEmpty(column.getSearchModes()))
{
column.getSearchModes().forEach(mode->{
if(!mode.equalsIgnoreCase("query"))
searchMap.put("n_"+column.getAlias().toLowerCase()+"_"+mode,column);
});
}
}
else
{
resultMap.put(column.getName().toLowerCase(), column.getName().toLowerCase());
if(!column.isComputed())
{
baseColumnMap.put(column.getName().toLowerCase(), column.getName().toLowerCase());
if(column.isPrimaryKey())
keyMap.put(column.getName().toLowerCase(),column.getName().toLowerCase());
}
}
}
@JsonIgnore
@JSONField(serialize = false)
public Map<String, String> getResultMap() {
if(columns!=null&&resultMap==null)
{
refreshColumnMaps();
}
return resultMap;
}
@JsonIgnore
@JSONField(serialize = false)
public Map<String, String> getBaseColumnMap() {
if(columns!=null&&baseColumnMap==null)
{
refreshColumnMaps();
}
return baseColumnMap;
}
@JsonIgnore
@JSONField(serialize = false)
public Map<String, String> getKeyMap() {
if(columns!=null&&keyMap==null)
{
refreshColumnMaps();
}
return keyMap;
}
@JsonIgnore
@JSONField(serialize = false)
public Map<String, Column> getSearchMap() {
if(columns!=null&&searchMap==null)
{
refreshColumnMaps();
}
return searchMap;
}
@JsonIgnore
@JSONField(serialize = false)
public Map<String, Column> getQuickSearch() {
if(columns!=null&&quickSearch==null)
{
refreshColumnMaps();
}
return quickSearch;
}
public Column getColumn(String name)
{
if(getColumnMaps()!=null)
{
return columnMaps.get(name.toLowerCase());
}
return null;
}
@JsonIgnore
@JSONField(serialize = false)
private Column lastModifyColumn;
@JsonIgnore
@JSONField(serialize = false)
private Column createTimeColumn;
@JsonIgnore
@JSONField(serialize = false)
private Column tenantColumn;
@JsonIgnore
@JSONField(serialize = false)
private boolean logicValid=false;
@JsonIgnore
@JSONField(serialize = false)
public boolean isLogicValid()
{
if(logicValid&&logicValidColumn==null) {
if (columns != null) {
for (Column col:columns) {
if (col.isLogicValid()) {
logicValidColumn = col;
return logicValid;
}
}
}
logicValid = false;
}
return logicValid;
}
@JsonIgnore
@JSONField(serialize = false)
private Column logicValidColumn;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Column{
@JSONField(ordinal = 1)
private String name;
@JSONField(ordinal = 2)
private String remarks;
@JSONField(ordinal = 3)
private String type;
@JSONField(ordinal = 4)
private Integer length;
@JSONField(ordinal = 5)
private Integer precision;
@JSONField(ordinal = 6)
private String defaultValue;
@JSONField(ordinal = 7)
private Boolean autoIncrement;
@JSONField(ordinal = 8)
private Boolean computed;
@JSONField(ordinal = 9)
private String alias;
@JSONField(ordinal = 10)
private String predefined;
@JSONField(ordinal = 11)
private Set<String> searchModes;
public Column setDefaultValue(String defaultValue)
{
if((!StringUtils.isEmpty(defaultValue))&&(!defaultValue.startsWith("$")))
this.defaultValue=defaultValue;
return this;
}
public Column putSearchModes(String searchModes)
{
if(!StringUtils.isEmpty(searchModes))
{
if(this.searchModes==null)
this.searchModes=new LinkedHashSet<>();
for(String mode:searchModes.split(","))
this.searchModes.add(mode);
}
return this;
}
public Column setAlias(String alias)
{
if((!StringUtils.isEmpty(name))&&(!name.equalsIgnoreCase(alias)))
this.alias=alias;
return this;
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isComputed()
{
return this.getComputed()!=null&&this.getComputed();
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isAutoIncrement()
{
return this.getAutoIncrement()!=null&&this.getAutoIncrement();
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isNullable()
{
return this.getConstraints()!=null&&this.getConstraints().isNullable();
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isPrimaryKey()
{
return this.getConstraints()!=null&&this.getConstraints().isPrimaryKey();
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isLogicValid()
{
return "LOGICVALID".equals(this.getPredefined());
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isLastModify()
{
return "UPDATEDATE".equals(this.getPredefined());
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isCreateTime()
{
return "CREATEDATE".equals(this.getPredefined());
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isTenant()
{
return "TENANT".equals(this.getPredefined());
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isText()
{
String type=this.getType().toUpperCase();
return type.indexOf("TEXT")>=0||type.indexOf("CHAR")>=0||type.indexOf("LOB")>=0;
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isNumber()
{
String type=this.getType().toUpperCase();
return type.indexOf("NUM")>=0||type.indexOf("FLOAT")>=0||type.indexOf("DOUBLE")>=0||type.indexOf("DECIMAL")>=0;
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isInt()
{
String type=this.getType().toUpperCase();
return type.indexOf("INT")==0;
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isDateTime()
{
String type=this.getType().toUpperCase();
return type.indexOf("DATE")>=0||type.indexOf("TIME")>=0;
}
@JSONField(ordinal = 12)
private Constraints constraints;
public Constraints getConstraints(boolean createWhenNotExist)
{
if(createWhenNotExist)
{
if(constraints==null)
constraints=new Constraints();
}
return constraints;
}
}
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Constraints{
private Boolean nullable;
private Boolean primaryKey;
private String primaryKeyName;
private String foreignKeyName;
private String referencedTableName;
private String referencedColumnNames;
@JsonIgnore
@JSONField(serialize = false)
public boolean isNullable()
{
return this.getNullable()!=null&&this.getNullable();
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isPrimaryKey()
{
return this.getPrimaryKey()!=null&&this.getPrimaryKey();
}
}
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonIgnoreProperties(ignoreUnknown = true)
public static class ForeignKeyConstraint{
private String baseColumnNames;
private String baseTableName;
private String constraintName;
private String referencedTableName;
private String referencedColumnNames;
private Boolean validate;
private String onUpdate;
private String onDelete;
}
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Segment {
private String name;
private String vendorProvider;
private String declare;
private String body;
private String format;
private Map params;
public Segment setVendorProvider(String vendorProvider) {
if (!StringUtils.isEmpty(vendorProvider))
this.vendorProvider = provider.get(vendorProvider.toLowerCase());
return this;
}
@JsonIgnore
@JSONField(serialize = false)
public String getSql()
{
if(!StringUtils.isEmpty(format))
return String.format(format,body);
return body;
}
}
@JSONField(ordinal = 11)
public List<Segment> segments;
public POSchema addSegment(Segment segment)
{
if(segments==null)
segments=new ArrayList<>();
segments.add(segment);
return this;
}
public static Map<String, String> provider = new HashMap<String, String>(){{
put("oracle", "oracle");
put("mysql", "mysql");
put("mysql5", "mysql");
put("postgresql", "postgresql");
put("mppdb", "postgresql");
put("dm", "oracle");
put("dameng", "oracle");
put("gbase", "oracle");
put("h2", "mysql");
}};
public Segment getSegment(String tag)
{
if(segments!=null)
{
for(Segment script:segments)
{
String key= DataObject.getStringValue(script.getName(),"").concat(".").concat(DataObject.getStringValue(script.getVendorProvider(),""));
if(key.equals(tag))
return script;
}
}
return null;
}
public Segment getSegment(String name, String type)
{
if(segments!=null)
{
if(StringUtils.isEmpty(type))
type=this.getDsType();
String vendorProvider=StringUtils.isEmpty(type)?"":provider.get(type.toLowerCase());
for(Segment script:segments)
{
if(script.getName().toLowerCase().indexOf(name.toLowerCase())>=0&&(StringUtils.isEmpty(vendorProvider)||script.getVendorProvider().indexOf(vendorProvider)>=0||StringUtils.isEmpty(script.getVendorProvider())))
return script;
}
}
else
{
segments=new ArrayList<>();
}
return null;
}
@JSONField(ordinal = 12)
public Segment defaultQueryScript;
public POSchema setDefaultQueryScriptSQL(String sql)
{
defaultQueryScript=new Segment().setName("default_query_script").setVendorProvider("").setBody(sql);
return this;
}
public Segment getDefaultQueryScript()
{
if(defaultQueryScript==null)
{
Segment segment=this.getSegment("dq-view-",this.getDsType());
if(segment==null)
segment=this.getSegment("dq-default-",this.getDsType());
if(segment!=null)
{
setDefaultQueryScriptSQL(segment.getBody());
return defaultQueryScript;
}
else if(!StringUtils.isEmpty(this.getDsType()))
{
segment=this.getSegment("dq-view-","");
if(segment==null)
segment=this.getSegment("dq-default-","");
if(segment!=null)
{
setDefaultQueryScriptSQL(segment.getBody().replace("`","").replace("[","").replace("]",""));
return defaultQueryScript;
}
}
defaultQueryScript=new Segment();
defaultQueryScript.setName("default_query_script");
defaultQueryScript.setVendorProvider("");
String sql="select ";
String cols="";
if(getBaseColumnMap()!=null)
{
cols= String.join(",",baseColumnMap.keySet());
}
else
cols="t1.*";
sql += (cols+" from "+name+" t1 ");
if(isLogicValid())
{
sql += " where t1."+this.getLogicValidCond();
}
defaultQueryScript.setBody(sql);
}
return defaultQueryScript;
}
@JsonIgnore
@JSONField(serialize = false)
public String logicValidCond;
@JsonIgnore
@JSONField(serialize = false)
public String logicValidDelCond;
@JSONField(serialize = false)
@JsonIgnore
private boolean built = false;
@JSONField(serialize = false)
@JsonIgnore
public synchronized POSchema build()
{
if(!built)
{
refreshColumnMaps();
built=true;
}
return this;
}
public POSchema writeTo(Path path)
{
return writeTo(this,path);
}
public static POSchema fromPath(Path path)
{
try {
if(!Files.exists(path))
throw new IllegalArgumentException("读取文件失败POSchema:"+path.toString());
return JSON.parseObject(Files.readAllBytes(path),POSchema.class);
} catch (Exception e) {
throw new RuntimeException("解析文件失败POSchema:"+path.toString());
}
}
public static POSchema writeTo(POSchema poSchema, Path path)
{
try {
File dir=path.getParent().toFile();
if(!dir.exists())
dir.mkdirs();
Files.write(path, JSON.toJSONBytes(poSchema));
} catch (Exception e) {
throw new RuntimeException("保存文件失败POSchema:"+path.toString());
}
return poSchema;
}
}
package com.ibizlab.codegen.model;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonIgnoreProperties(ignoreUnknown = true)
public class PojoOption extends DataObj
{
public PojoOption set(String key, Object value)
{
this.put(key,value);
return this;
}
public PojoOption setAll(Map map)
{
if(map!=null)
this.putAll(map);
else if(this.size()==0)
return null;
return this;
}
public String getName() {
return this.getStringValue("name",this.getStringValue("code_name"));
}
public PojoOption setName(String name) {
return this.set("name",name);
}
public String getSystem(){
return this.getStringValue("system_id",this.getStringValue("system",this.getStringValue("system_name")));
}
public String getSystemName(){
return this.getStringValue("system_name",this.getStringValue("system",this.getStringValue("system_id")));
}
public String getPackage(){
return this.getStringValue("module_name",this.getStringValue("module",this.getStringValue("moduleid")));
}
public String getTableName(){
return this.getStringValue("table_name",getName());
}
public String getEntityName(){
return this.getStringValue("entity_name","");
}
public String getCodeName(){
return this.getStringValue("code_name","");
}
public String getDefaultDataSoruce(){
return this.getStringValue("ds_name",this.getSystem()+"-master");
}
public List<String> getDsTypes(){
List<String> dsTypes=new ArrayList<>();
String strDsTypes= this.getStringValue("ds_types");
for(String dsType:strDsTypes.split(","))
dsTypes.add(dsType);
return dsTypes;
}
public PojoOption setDsTypes(String dsTypes){
return this.set("ds_types",dsTypes);
}
public String getDefaultQueryScript()
{
return this.getStringValue("default_query_script");
}
public Boolean isLogicValid() {
return this.getBooleanValue("logic_valid");
}
public PojoOption setLogicValid(Boolean logicValid) {
return this.set("logic_valid",logicValid);
}
public String getLogicVal()
{
return this.getStringValue("logicval","1");
}
public PojoOption setLogicVal(String logicval) {
return this.set("logicval",logicval);
}
public String getLogicDelVal()
{
return this.getStringValue("logicdelval","0");
}
public PojoOption setLogicDelVal(String logicdelval) {
return this.set("logicdelval",logicdelval);
}
public String getFieldName() {
return this.getStringValue("field_name",getName());
}
public PojoOption setFieldName(String code) {
return this.set("field_name",code);
}
public String getRelationName() {
return this.getStringValue("relation_name");
}
public PojoOption setRelationName(String relationName) {
return this.set("relation_name",relationName);
}
public String getRelationCodeName() {
return this.getStringValue("relation_code_name");
}
public PojoOption setRelationCodeName(String relationCodeName) {
return this.set("relation_code_name",relationCodeName);
}
public String getRefEntityName() {
return this.getStringValue("ref_entity_name");
}
public PojoOption setRefEntityName(String refEntityName) {
return this.set("ref_entity_name",refEntityName);
}
public String getRefTableName() {
return this.getStringValue("ref_table_name",getRefEntityName());
}
public PojoOption setRefTableName(String refTableName) {
return this.set("ref_table_name",refTableName);
}
public String getRefFieldName() {
return this.getStringValue("ref_field_name");
}
public PojoOption setRefFieldName(String refFieldName) {
return this.set("ref_field_name",refFieldName);
}
public String getRefFieldCodeName() {
return this.getStringValue("ref_field_code_name");
}
public PojoOption setRefFieldCodeName(String refFieldCodeName) {
return this.set("ref_field_code_name",refFieldCodeName);
}
public Boolean isKeyField() {
return this.getBooleanValue("key_field");
}
public PojoOption setKeyField(Boolean keyField) {
return this.set("key_field",keyField);
}
public Boolean isMajorField() {
return this.getBooleanValue("major_field");
}
public PojoOption setMajorField(Boolean majorField) {
return this.set("major_field",majorField);
}
public String getUnionKey() {
return this.getStringValue("union_key");
}
public PojoOption setUnionKey(String unionKey) {
return this.set("union_key",unionKey);
}
public Boolean isPhysicalField() {
return this.getBooleanValue("physical_field",this.getBooleanValue("Persistent",true));
}
public PojoOption setPhysicalField(Boolean physicalField) {
return this.set("physical_field",physicalField);
}
public Boolean isNullable() {
return this.getBooleanValue("nullable",!this.getBooleanValue("required",true));
}
public PojoOption setNullable(Boolean nullable) {
return this.set("nullable",nullable);
}
public String getFieldType() {
return this.getStringValue("field_type");
}
public PojoOption setFieldType(String fieldType) {
return this.set("field_type",fieldType);
}
public String getPredefined() {
return this.getStringValue("predefined");
}
public PojoOption setPredefined(String predefined) {
return this.set("predefined",predefined);
}
public String getDict() {
return this.getStringValue("dict");
}
public PojoOption setDict(String dict) {
return this.set("dict",dict);
}
public String getDefaultValue() {
return this.getStringValue("default_value");
}
public PojoOption setDefaultValue(String defaultValue) {
return this.set("default_value",defaultValue);
}
public String getDataType() {
return this.getStringValue("data_type");
}
public PojoOption setDataType(String dataType) {
return this.set("data_type",dataType);
}
public Integer getDataLength() {
return this.getIntegerValue("data_length",this.getIntegerValue("length",null));
}
public PojoOption setDataLength(Integer dataLength) {
return this.set("data_length",dataLength);
}
public Integer getDataPreci() {
return this.getIntegerValue("data_preci",this.getIntegerValue("precision",this.getIntegerValue("preci",null)));
}
public PojoOption setDataPreci(Integer dataPreci) {
return this.set("data_preci",dataPreci);
}
public String getExpression() {
return this.getStringValue("expression");
}
public PojoOption setExpression(String expression) {
return this.set("expression",expression);
}
public String getSearchModes() {
return this.getStringValue("search_modes");
}
public PojoOption setSearchModes(String search_modes) {
return this.set("search_modes",search_modes);
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isLogicValidField()
{
return "LOGICVALID".equals(this.getPredefined());
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isLastModifyField()
{
return "UPDATEDATE".equals(this.getPredefined());
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isCreateTimeField()
{
return "CREATEDATE".equals(this.getPredefined());
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isUnionKeyField()
{
return !StringUtils.isEmpty(this.getUnionKey());
}
}
package com.ibizlab.codegen.model;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.ibizlab.codegen.utils.Inflector;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.springframework.util.StringUtils;
import java.io.File;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonIgnoreProperties(ignoreUnknown = true)
public class PojoSchema {
@JSONField(ordinal = 1)
private String id;
@JSONField(ordinal = 2)
private String type;
@JSONField(serialize = false)
@JsonIgnore
private String name;
@JSONField(serialize = false)
@JsonIgnore
public String getName()
{
if(name==null)
name=this.getOptions().getName();
return name;
}
public PojoSchema setName(String name)
{
if(!StringUtils.isEmpty(name))
{
this.name=name;
if(options==null)
options=new PojoOption();
options.setName(name);
}
return this;
}
@JSONField(serialize = false)
@JsonIgnore
public String getCodeName()
{
return this.getOptions().getStringValue("code_name",this.getName());
}
@JSONField(serialize = false)
@JsonIgnore
public String getSystem()
{
return this.getOptions().getSystem();
}
@JSONField(serialize = false)
@JsonIgnore
public String getDefaultDataSoruce()
{
return this.getOptions().getDefaultDataSoruce();
}
@JSONField(serialize = false)
@JsonIgnore
public String getDefaultTableName()
{
return this.getOptions().getTableName();
}
@JSONField(serialize = false)
@JsonIgnore
public String getPackage()
{
return this.getOptions().getSystem();
}
@JSONField(ordinal = 3)
private String title;
@JSONField(ordinal = 4)
private String description;
@JSONField(ordinal = 5)
private Integer propertyOrder;
@JSONField(ordinal = 6)
private PojoOption options;
public PojoOption getOptions()
{
if(options==null)
options=new PojoOption();
return options;
}
public PojoSchema setOptions(PojoOption options)
{
if(options==null)
return this;
if(this.options!=null)
options.putAll(this.options);
this.options=options;
return this;
}
@JSONField(ordinal = 7)
private String ref;
@JSONField(serialize = false)
@JsonIgnore
public PojoSchema copy()
{
return JSONObject.parseObject(JSON.toJSONString(this),PojoSchema.class);
}
@JSONField(serialize = false)
@JsonIgnore
private boolean built = false;
@JSONField(serialize = false)
@JsonIgnore
public PojoSchema build()
{
if((!built)&& Type.object.getCode().equalsIgnoreCase(this.getType()))
{
if(properties!=null)
{
properties.values().forEach(prop->{
PojoSchema item=null;
if(Type.object.getCode().equalsIgnoreCase(prop.getType())&&(!StringUtils.isEmpty(prop.getRef())))
item=prop;
else if(Type.array.getCode().equalsIgnoreCase(prop.getType())
&&prop.getItems()!=null&& Type.object.getCode().equalsIgnoreCase(prop.getItems().getType())
&&(!StringUtils.isEmpty(prop.getItems().getRef())))
item=prop.getItems();
else
return;
});
}
built=true;
}
return this;
}
/// object
@JSONField(ordinal = 11)
private Map<String,PojoSchema> properties;
public PojoSchema setProperties(Map<String,PojoSchema> properties)
{
if(properties!=null)
{
properties.keySet().forEach(key->{
properties.get(key).setName(key).setOwner(this);
});
this.properties=properties;
}
return this;
}
public Map<String,PojoSchema> getProperties()
{
if(!Type.object.getCode().equals(this.type))
{
properties=null;
return properties;
}
if(properties==null)
properties = new LinkedHashMap<>();
return properties;
}
public PojoSchema addProperty(String name, PojoSchema property)
{
if(StringUtils.isEmpty(name))
return this;
Map<String,PojoSchema> props = this.getProperties();
if(props!=null) {
props.put(name, property.setName(name).setOwner(this));
}
return this;
}
@JsonIgnore
@JSONField(serialize = false)
private List<PojoSchema> references;
public List<PojoSchema> getReferences()
{
if(references==null)
{
references=new ArrayList<>();
getProperties().values().forEach(prop->{
if(Type.object.getCode().equalsIgnoreCase(prop.getType())&&(!StringUtils.isEmpty(prop.getOptions().getRelationName()))) {
references.add(prop);
}
});
}
return references;
}
@JsonIgnore
@JSONField(serialize = false)
private Map<String,PojoSchema> referenceMap;
@JsonIgnore
@JSONField(serialize = false)
public Map<String,PojoSchema> getReferenceMap()
{
if(referenceMap==null)
{
referenceMap=new LinkedHashMap<>();
getProperties().keySet().forEach(key->{
PojoSchema prop=getProperties().get(key);
if(Type.object.getCode().equalsIgnoreCase(prop.getType())&&(!StringUtils.isEmpty(prop.getOptions().getRelationName()))) {
referenceMap.put(key, prop);
if(!key.equals(key.toLowerCase()))
referenceMap.put(key.toLowerCase(),prop);
referenceMap.put(prop.getOptions().getRelationName(),prop);
if(!StringUtils.isEmpty(prop.getOptions().getEntityName())) {
if(!referenceMap.containsKey(prop.getOptions().getEntityName()))
referenceMap.put(prop.getOptions().getEntityName(), prop);
if(!referenceMap.containsKey(prop.getOptions().getEntityName().toLowerCase()))
referenceMap.put(prop.getOptions().getEntityName().toLowerCase(),prop);
}
if(!StringUtils.isEmpty(prop.getOptions().getCodeName())) {
if(!referenceMap.containsKey(prop.getOptions().getCodeName()))
referenceMap.put(prop.getOptions().getCodeName(), prop);
if(!referenceMap.containsKey(prop.getOptions().getCodeName().toLowerCase()))
referenceMap.put(prop.getOptions().getCodeName().toLowerCase(), prop);
}
String pluralize= Inflector.getInstance().pluralize(StringUtils.isEmpty(prop.getOptions().getCodeName())?prop.getOptions().getEntityName():prop.getOptions().getCodeName()).toLowerCase();
if(!referenceMap.containsKey(pluralize))
referenceMap.put(pluralize, prop);
}
});
}
return referenceMap;
}
public PojoSchema getRefSchema(String tag)
{
if(getReferenceMap()!=null)
{
return this.getReferenceMap().get(tag);
}
return null;
}
public Map<String,PojoSchema> getRefProperties()
{
Map<String,PojoSchema> refProperties=new LinkedHashMap<>();
if(this.getOwner()!=null&& Type.object.getCode().equalsIgnoreCase(this.getType())&&(!StringUtils.isEmpty(this.getOptions().getRelationName())))
{
this.getOwner().getProperties().entrySet().forEach(entry-> {
String key=entry.getKey();
if(key.equals(this.getName()))
return;
PojoSchema prop = entry.getValue();
if((!StringUtils.isEmpty(prop.getOptions().getRelationName()))&&prop.getOptions().getRelationName().equals(this.getOptions().getRelationName()))
{
refProperties.put(key,prop);
}
});
}
return refProperties;
}
public Map<String,PojoSchema> getRefProperties(String tag)
{
Map<String,PojoSchema> refProperties=new LinkedHashMap<>();
PojoSchema refSchema=this.getRefSchema(tag);
if(refSchema!=null)
{
getProperties().entrySet().forEach(entry-> {
String key=entry.getKey();
if(key.equals(refSchema.getName()))
return;
PojoSchema prop = entry.getValue();
if((!StringUtils.isEmpty(prop.getOptions().getRelationName()))&&prop.getOptions().getRelationName().equals(refSchema.getOptions().getRelationName()))
{
refProperties.put(key,prop);
}
});
}
return refProperties;
}
@JSONField(serialize = false)
@JsonIgnore
private PojoSchema owner;
@JSONField(ordinal = 12)
private Set<String> required;
public Set<String> getRequired()
{
if(!Type.object.getCode().equals(this.type))
{
required=null;
return required;
}
if(required==null&&properties!=null)
{
required=new LinkedHashSet<>();
properties.values().forEach(prop->{
if (!prop.getOptions().isNullable())
required.add(prop.getName());
});
}
return required;
}
@JSONField(ordinal = 13)
private Integer minProperties;
@JSONField(ordinal = 14)
private Integer maxProperties;
@JsonIgnore
@JSONField(serialize = false)
private Map<String,PojoSchema> keyMap;
@JsonIgnore
@JSONField(serialize = false)
private PojoSchema keyProperty;
@JsonIgnore
@JSONField(serialize = false)
private Map<String,PojoSchema> unionKeys;
public PojoSchema getKeyProperty() {
if(keyProperty==null)
getKeyMap();
return keyProperty;
}
@JsonIgnore
@JSONField(serialize = false)
public synchronized Map<String,PojoSchema> getKeyMap()
{
if(Type.object.getCode().equals(this.type))
{
if(keyMap==null)
{
List<PojoSchema> keys=new ArrayList<>();
keyMap=new LinkedHashMap<>();
getProperties().values().forEach(sub->{
if(Type.array.getCode().equals(sub.getType())|| Type.object.getCode().equals(sub.getType()))
return;
if(sub.getOptions().isKeyField())
keyProperty=sub;
if(sub.getOptions().isKeyField()&&sub.getOptions().isPhysicalField())
keys.add(sub);
});
if(keys.isEmpty())
{
getProperties().values().forEach(sub->{
if(Type.array.getCode().equals(sub.getType())|| Type.object.getCode().equals(sub.getType()))
return;
if(sub.getOptions().isUnionKeyField()&&sub.getOptions().isPhysicalField())
keys.add(sub);
});
}
if(keys.size()>0)
keys.sort( (o1, o2) -> o1.getOptions().getUnionKey().compareTo(o2.getOptions().getUnionKey()) );
keys.forEach(sub->keyMap.put(sub.getOptions().getFieldName(),sub));
}
}
return keyMap;
}
@JsonIgnore
@JSONField(serialize = false)
public synchronized Map<String,PojoSchema> getUnionKeys()
{
if(Type.object.getCode().equals(this.type)) {
if (unionKeys == null) {
List<PojoSchema> keys=new ArrayList<>();
Map<String,PojoSchema> unions=new LinkedHashMap<>();
getProperties().values().forEach(sub->{
if(Type.array.getCode().equals(sub.getType())|| Type.object.getCode().equals(sub.getType()))
return;
if(sub.getOptions().isUnionKeyField()&&sub.getOptions().isPhysicalField())
keys.add(sub);
});
if(keys.size()>0) {
keys.sort((o1, o2) -> o1.getOptions().getUnionKey().compareTo(o2.getOptions().getUnionKey()));
keys.forEach(sub -> unions.put(sub.getOptions().getFieldName(),sub));
unionKeys=unions;
}
}
}
return unionKeys;
}
//// array
@JSONField(ordinal = 21)
private PojoSchema items;
@JSONField(ordinal = 22)
private Integer minItems;
@JSONField(ordinal = 23)
private Boolean uniqueItems;
public void setUniqueItems(Boolean uniqueItems) {
this.uniqueItems = uniqueItems;
}
/// String
@JSONField(ordinal = 33)
private Integer minLength;
@JSONField(ordinal = 34)
private Integer maxLength;
@JSONField(ordinal = 35)
private String pattern;
@JSONField(ordinal = 36)
private String format;
/// integer number
@JSONField(ordinal = 41)
private BigDecimal minimum;
@JSONField(ordinal = 42)
private BigDecimal maximum;
@JSONField(ordinal = 43)
private Boolean exclusiveMinimum;
@JSONField(ordinal = 44)
private Boolean exclusiveMaximum;
@JSONField(ordinal = 45)
private Integer multipleOf;
public PojoSchema writeTo(Path path)
{
return writeTo(this,path);
}
public static PojoSchema fromPath(Path path)
{
try {
if(!Files.exists(path))
throw new IllegalArgumentException("读取文件失败PojoSchema:"+path.toString());
return JSON.parseObject(Files.readAllBytes(path),PojoSchema.class);
} catch (Exception e) {
throw new RuntimeException("解析文件失败PojoSchema:"+path.toString());
}
}
public static PojoSchema writeTo(PojoSchema pojoSchema, Path path)
{
try {
File dir=path.getParent().toFile();
if(!dir.exists())
dir.mkdirs();
Files.write(path, JSON.toJSONBytes(pojoSchema));
} catch (Exception e) {
throw new RuntimeException("保存文件失败PojoSchema:"+path.toString());
}
return pojoSchema;
}
public static enum Type {
string("string", "字符"),
integer("integer", "整型"),
number("number", "数值"),
object("object", "对象"),
array("array", "数组");
public final String code;
public final String name;
private Type(String code, String name) {
this.code = code;
this.name = name;
}
public String getCode() {
return code;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Type{" +
"code='" + code + '\'' +
", name='" + name + '\'' +
'}';
}
}
}
package com.ibizlab.codegen.model;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ibizlab.codegen.lite.*;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.util.LinkedHashMap;
import java.util.Map;
public class TransUtils {
public static PojoSchema EntityModelModel2Schema(EntityModel entityModel)
{
PojoSchema pojoSchema=new PojoSchema().setName(entityModel.getEntityName()).setType("object").setTitle(entityModel.getLogicName()).setId(entityModel.getEntityId())
.setOptions(new PojoOption().setDsTypes(String.join(",",entityModel.getDsTypes())).setLogicValid(entityModel.isLogicValid()).setLogicVal(entityModel.getLogicVal()).setLogicDelVal(entityModel.getLogicDelVal()));
pojoSchema.getOptions().setAll(JSONObject.parseObject(JSON.toJSONString(entityModel.getEntity()))).remove("ext_params");
int order=1;
for(FieldModel fieldModel:entityModel.getFields())
{
String propType=fieldModel.getPropType();
PojoSchema sub=null;
if("date".equals(propType))
sub=new PojoSchema().setType(PojoSchema.Type.string.getCode()).setFormat("date");
else if("date-time".equals(propType))
sub=new PojoSchema().setType(PojoSchema.Type.string.getCode()).setFormat("date-time");
else
sub=new PojoSchema().setType(propType);
sub.setName(fieldModel.getCodeName()).setTitle(fieldModel.getField().getFieldLogicName()).setPropertyOrder(order)
.setOptions(new PojoOption().setAll(JSONObject.parseObject(JSON.toJSONString(fieldModel.getField()))));
Object searchModes=fieldModel.getField().get("search_modes");
if(!ObjectUtils.isEmpty(searchModes))
sub.getOptions().setSearchModes(searchModes.toString());
Object defaultValue=fieldModel.getField().get("default_value");
if(!ObjectUtils.isEmpty(defaultValue))
sub.getOptions().setDefaultValue(defaultValue.toString());
sub.getOptions().remove("ext_params");
if("PICKUP".equals(fieldModel.getField().getFieldType())&&fieldModel.isPhysicalField())
{
if(!StringUtils.isEmpty(sub.getOptions().getRelationCodeName()))
{
RelationshipModel relationshipModel=entityModel.getRefMaps().get(sub.getOptions().getRelationCodeName());
if(relationshipModel!=null&&(!StringUtils.isEmpty(relationshipModel.getTableName())))
sub.getOptions().setRefTableName(relationshipModel.getTableName());
}
String smode=sub.getOptions().getSearchModes();
if((!smode.startsWith("eq"))&&smode.indexOf(",eq")<0)
sub.getOptions().setSearchModes(smode.concat(StringUtils.isEmpty(smode)?"":",").concat("eq"));
}
pojoSchema.addProperty(sub.getName(),sub);
order++;
}
if(entityModel.getReferences()!=null)
{
for(RelationshipModel rel:entityModel.getReferences())
{
PojoSchema sub=new PojoSchema().setType(PojoSchema.Type.object.getCode()).setName(rel.getCodeName()).setTitle(rel.getCodeName()+rel.getEntityLogicName())
.setPropertyOrder(order).setOptions(new PojoOption()
.set("logic_name",rel.getEntityLogicName())
.set("entity_name",rel.getEntityName())
.set("system_id",(StringUtils.isEmpty(rel.getSystemId())?entityModel.getSystemId():rel.getSystemId()))
.set("entity_id",rel.getEntityId()).set("code_name",rel.getEntityCodeName())
.set("table_name",rel.getTableName()).set("ds_name",rel.getDataSourceName())
.set("relation_name",rel.getRelation().getName())
.set("relation",JSONObject.parseObject(JSON.toJSONString(rel.getRelation()), MetaRelationshipModel.class))
)
.setRef("domain."+rel.getEntityName());
pojoSchema.addProperty(sub.getName(),sub);
order++;
}
}
if(entityModel.getNesteds()!=null)
{
for(RelationshipModel nest:entityModel.getNesteds())
{
PojoSchema sub=new PojoSchema().setType(PojoSchema.Type.array.getCode()).setName(nest.getCodeName()).setTitle(nest.getCodeName()+nest.getEntityLogicName())
.setPropertyOrder(order).setOptions(new PojoOption()
.set("logic_name",nest.getEntityLogicName())
.set("entity_name",nest.getEntityName())
.set("system_id",(StringUtils.isEmpty(nest.getSystemId())?entityModel.getSystemId():nest.getSystemId()))
.set("entity_id",nest.getEntityId()).set("code_name",nest.getEntityCodeName())
.set("table_name",nest.getTableName()).set("ds_name",nest.getDataSourceName())
.set("relation_name",nest.getRelation().getName())
.set("relation",JSONObject.parseObject(JSON.toJSONString(nest.getRelation()), MetaRelationshipModel.class))
)
.setItems(new PojoSchema().setType(PojoSchema.Type.object.getCode()).setName(nest.getEntityName()).setTitle(nest.getEntityLogicName())
.setRef("domain."+nest.getEntityName())
.setOptions(new PojoOption()
.set("logic_name",nest.getEntityLogicName())
.set("entity_name",nest.getEntityName())
.set("system_id",(StringUtils.isEmpty(nest.getSystemId())?entityModel.getSystemId():nest.getSystemId()))
.set("entity_id",nest.getEntityId()).set("code_name",nest.getEntityCodeName())
.set("table_name",nest.getTableName()).set("ds_name",nest.getDataSourceName())
)
);
pojoSchema.addProperty(sub.getName(),sub);
order++;
}
}
return pojoSchema;
}
public static POSchema PojoSchema2PO(PojoSchema pojoSchema)
{
POSchema poSchema=new POSchema().setName(pojoSchema.getDefaultTableName()).setDefaultDataSource(pojoSchema.getDefaultDataSoruce())
.setRemarks(pojoSchema.getTitle()).setLogicVal(pojoSchema.getOptions().getLogicVal()).setLogicDelVal(pojoSchema.getOptions().getLogicDelVal());
for(String name:pojoSchema.getProperties().keySet())
{
PojoSchema sub=pojoSchema.getProperties().get(name);
String dataType=sub.getOptions().getDataType();
Integer length=sub.getOptions().getDataLength();
Integer precision=sub.getOptions().getDataPreci();
POSchema.Column column=new POSchema.Column().setName(sub.getOptions().getFieldName()).setAlias(name).setRemarks(sub.getTitle()).setDefaultValue(sub.getOptions().getDefaultValue()).setPredefined(sub.getOptions().getPredefined()).setLength(length);
if(PojoSchema.Type.object.getCode().equals(sub.getType())||PojoSchema.Type.array.getCode().equals(sub.getType()))
{
if(!sub.getOptions().isPhysicalField())
continue;
if(StringUtils.isEmpty(dataType))dataType="TEXT";
column.setType(dataType);
column.setLength(null);
}
else if(PojoSchema.Type.string.getCode().equals(sub.getType())&&(!StringUtils.isEmpty(sub.getFormat())))
{
if(StringUtils.isEmpty(dataType)&&(sub.getFormat().indexOf("date")>=0))
dataType="DATETIME";
else
dataType="VARCHAR";
column.setType(dataType);
}
else if(PojoSchema.Type.integer.getCode().equals(sub.getType()) )
{
if(StringUtils.isEmpty(dataType))dataType="INT";
column.setType(dataType);
}
else if(PojoSchema.Type.number.getCode().equals(sub.getType()) )
{
if(StringUtils.isEmpty(dataType))dataType="NUMBER";
column.setType(dataType);
}
else {
if(StringUtils.isEmpty(dataType))dataType="VARCHAR";
column.setType(dataType);
}
if(column.isNumber())
column.setPrecision(precision);
if((pojoSchema.getRequired()!=null&&pojoSchema.getRequired().contains(name))||(!pojoSchema.getOptions().isNullable()))
column.getConstraints(true).setNullable(false);
if(pojoSchema.getKeyMap()!=null&&pojoSchema.getKeyMap().containsKey(column.getName())) {
String primaryKeyName="PK_"+poSchema.getName().toUpperCase()+"_"+ column.getName().toUpperCase();
column.getConstraints(true).setPrimaryKey(true).setPrimaryKeyName(primaryKeyName);
}
if(sub.getOptions().isLogicValidField())
{
if(!StringUtils.isEmpty(pojoSchema.getOptions().getLogicVal()))
column.setDefaultValue(pojoSchema.getOptions().getLogicVal());
else
column.setDefaultValue("1");
}
if(!StringUtils.isEmpty(sub.getOptions().getSearchModes()))
column.putSearchModes(sub.getOptions().getSearchModes());
if("PICKUP".equals(sub.getOptions().getFieldType())&&sub.getOptions().isPhysicalField())
{
PojoSchema relationshipModel=pojoSchema.getRefSchema(sub.getOptions().getRelationName());
String fkName=sub.getOptions().getRelationName().toUpperCase();
if((!StringUtils.isEmpty(relationshipModel.getOptions().getRefTableName()))&&(!StringUtils.isEmpty(fkName))) {
column.getConstraints(true).setReferencedTableName(relationshipModel.getOptions().getRefTableName()).setReferencedColumnNames(sub.getOptions().getRefFieldName()).setForeignKeyName(fkName);
poSchema.addForeignKeyConstraint(new POSchema.ForeignKeyConstraint().setConstraintName(fkName).setBaseTableName(poSchema.getName()).setBaseColumnNames(column.getName()).setReferencedTableName(relationshipModel.getOptions().getRefTableName()).setReferencedColumnNames(sub.getOptions().getRefFieldName()));
}
}
else if((!StringUtils.isEmpty(sub.getOptions().getRelationName()))) {
PojoSchema relationshipModel=pojoSchema.getRefSchema(sub.getOptions().getRelationName());
if(relationshipModel!=null&&(!StringUtils.isEmpty(relationshipModel.getOptions().getTableName()))) {
column.getConstraints(true).setReferencedTableName(relationshipModel.getOptions().getTableName())
.setReferencedColumnNames(sub.getOptions().getRefFieldName());
}
}
if(!sub.getOptions().isPhysicalField())
poSchema.addTransient(column.setComputed(true));
else
poSchema.addColumn(column);
}
String defaultQueryScript=pojoSchema.getOptions().getDefaultQueryScript();
if(!StringUtils.isEmpty(defaultQueryScript))
poSchema.setDefaultQueryScriptSQL(defaultQueryScript);
return poSchema;
}
public static POSchema PojoSchema2DocumentPO(PojoSchema pojoSchema)
{
POSchema poSchema=new POSchema().setName(pojoSchema.getCodeName().toLowerCase()).setDefaultDataSource(pojoSchema.getDefaultDataSoruce())
.setRemarks(pojoSchema.getTitle()).setLogicVal(pojoSchema.getOptions().getLogicVal()).setLogicDelVal(pojoSchema.getOptions().getLogicDelVal());
for(String name:pojoSchema.getProperties().keySet())
{
PojoSchema sub=pojoSchema.getProperties().get(name);
String dataType=sub.getOptions().getDataType();
Integer length=sub.getOptions().getDataLength();
Integer precision=sub.getOptions().getDataPreci();
POSchema.Column column=new POSchema.Column().setName(name).setAlias(name).setRemarks(sub.getTitle()).setDefaultValue(sub.getOptions().getDefaultValue()).setPredefined(sub.getOptions().getPredefined()).setLength(length);
if(PojoSchema.Type.object.getCode().equals(sub.getType())||PojoSchema.Type.array.getCode().equals(sub.getType()))
{
if(!sub.getOptions().isPhysicalField())
continue;
if(StringUtils.isEmpty(dataType))dataType="TEXT";
column.setType(dataType);
column.setLength(null);
}
else if(PojoSchema.Type.string.getCode().equals(sub.getType())&&(!StringUtils.isEmpty(sub.getFormat())))
{
if(StringUtils.isEmpty(dataType)&&(sub.getFormat().indexOf("date")>=0))
dataType="DATETIME";
else
dataType="VARCHAR";
column.setType(dataType);
}
else if(PojoSchema.Type.integer.getCode().equals(sub.getType()) )
{
if(StringUtils.isEmpty(dataType))dataType="INT";
column.setType(dataType);
}
else if(PojoSchema.Type.number.getCode().equals(sub.getType()) )
{
if(StringUtils.isEmpty(dataType))dataType="NUMBER";
column.setType(dataType);
}
else {
if(StringUtils.isEmpty(dataType))dataType="VARCHAR";
column.setType(dataType);
}
if(column.isNumber())
column.setPrecision(precision);
if((pojoSchema.getRequired()!=null&&pojoSchema.getRequired().contains(name))||(!pojoSchema.getOptions().isNullable()))
column.getConstraints(true).setNullable(false);
if(pojoSchema.getKeyMap()!=null&&pojoSchema.getKeyMap().containsKey(column.getName())) {
String primaryKeyName="PK_"+poSchema.getName().toUpperCase()+"_"+ column.getName().toUpperCase();
column.getConstraints(true).setPrimaryKey(true).setPrimaryKeyName(primaryKeyName);
}
if(sub.getOptions().isLogicValidField())
{
if(!StringUtils.isEmpty(pojoSchema.getOptions().getLogicVal()))
column.setDefaultValue(pojoSchema.getOptions().getLogicVal());
else
column.setDefaultValue("1");
}
if(!StringUtils.isEmpty(sub.getOptions().getSearchModes()))
column.putSearchModes(sub.getOptions().getSearchModes());
if("PICKUP".equals(sub.getOptions().getFieldType())&&sub.getOptions().isPhysicalField())
{
PojoSchema relationshipModel=pojoSchema.getRefSchema(sub.getOptions().getRelationName());
String fkName=sub.getOptions().getRelationName().toUpperCase();
if((!StringUtils.isEmpty(relationshipModel.getOptions().getRefTableName()))&&(!StringUtils.isEmpty(fkName))) {
column.getConstraints(true).setReferencedTableName(relationshipModel.getOptions().getRefTableName()).setReferencedColumnNames(sub.getOptions().getRefFieldName()).setForeignKeyName(fkName);
poSchema.addForeignKeyConstraint(new POSchema.ForeignKeyConstraint().setConstraintName(fkName).setBaseTableName(poSchema.getName()).setBaseColumnNames(column.getName()).setReferencedTableName(relationshipModel.getOptions().getRefTableName()).setReferencedColumnNames(sub.getOptions().getRefFieldName()));
}
}
else if((!StringUtils.isEmpty(sub.getOptions().getRelationName()))) {
PojoSchema relationshipModel=pojoSchema.getRefSchema(sub.getOptions().getRelationName());
if(relationshipModel!=null&&(!StringUtils.isEmpty(relationshipModel.getOptions().getTableName()))) {
column.getConstraints(true).setReferencedTableName(relationshipModel.getOptions().getTableName())
.setReferencedColumnNames(sub.getOptions().getRefFieldName());
}
}
if(!sub.getOptions().isPhysicalField())
poSchema.addTransient(column.setComputed(true));
else
poSchema.addColumn(column);
}
String defaultQueryScript=pojoSchema.getOptions().getDefaultQueryScript();
if(!StringUtils.isEmpty(defaultQueryScript))
poSchema.setDefaultQueryScriptSQL(defaultQueryScript);
return poSchema;
}
public static POSchema EntityModelModel2PO(EntityModel entityModel, String dsType) {
final String dataSourceType=dsType.toLowerCase();
POSchema poSchema=new POSchema().setDsType(dataSourceType).setName(entityModel.getTableName(dataSourceType)).setDefaultDataSource(entityModel.getDsName())
.setRemarks(entityModel.getLogicName()).setLogicVal(entityModel.getLogicVal()).setLogicDelVal(entityModel.getLogicDelVal());
Map<String,FieldModel> keyMap=new LinkedHashMap<>();
Map<String,RelationshipModel> relationshipModelMap = new LinkedHashMap<>();
if(entityModel.getKeyFields()!=null)entityModel.getKeyFields().forEach(model->keyMap.put(model.getColumnName(),model));
if(entityModel.getReferences()!=null)entityModel.getReferences().forEach(model->relationshipModelMap.put(model.getRelation().getName(),model));
int order = 1;
for (FieldModel fieldModel : entityModel.getFields()) {
MetaFieldModel sub=fieldModel.getField();
String colName=fieldModel.getColumnName(dataSourceType);
Integer length=sub.getDataLength();
Integer precision=sub.getDataPreci();
POSchema.Column column=new POSchema.Column().setName(colName).setAlias(sub.getCodeName()).setRemarks(sub.getFieldLogicName()).setPredefined(sub.getPredefined()).setLength(length).setType(sub.getDataType());
if(column.isNumber())
column.setPrecision(precision);
if(sub.getNullable()!=null&&sub.getNullable()==0)
column.getConstraints(true).setNullable(false);
if(keyMap.containsKey(column.getName())) {
String primaryKeyName="PK_"+poSchema.getName().toUpperCase()+"_"+ column.getName().toUpperCase();
column.getConstraints(true).setPrimaryKey(true).setPrimaryKeyName(primaryKeyName);
}
if(fieldModel.isLogicValidField())
{
if(!StringUtils.isEmpty(entityModel.getLogicVal()))
column.setDefaultValue(entityModel.getLogicVal());
else
column.setDefaultValue("1");
}
Object searchModes=fieldModel.getField().get("search_modes");
if(searchModes!=null)
column.putSearchModes(searchModes.toString());
if("PICKUP".equals(sub.getFieldType())&&fieldModel.isPhysicalField())
{
RelationshipModel relationshipModel=relationshipModelMap.get(sub.getRelationName());
String fkName=sub.getRelationName().toUpperCase();
if(relationshipModel!=null&&(!StringUtils.isEmpty(relationshipModel.getTableName()))&&(!StringUtils.isEmpty(fkName))) {
column.getConstraints(true).setReferencedTableName(relationshipModel.getTableName())
.setReferencedColumnNames(sub.getRefFieldName()).setForeignKeyName(fkName);
poSchema.addForeignKeyConstraint(new POSchema.ForeignKeyConstraint().setConstraintName(fkName)
.setBaseTableName(poSchema.getName()).setBaseColumnNames(column.getName())
.setReferencedTableName(relationshipModel.getTableName()).setReferencedColumnNames(sub.getRefFieldName()));
}
if(!column.getSearchModes().contains("eq"))
column.getSearchModes().add("eq");
}
else if((!StringUtils.isEmpty(sub.getRelationName()))) {
RelationshipModel relationshipModel = relationshipModelMap.get(sub.getRelationName());
String fkName=sub.getRelationName().toUpperCase();
if(relationshipModel!=null&&(!StringUtils.isEmpty(relationshipModel.getTableName()))&&(!StringUtils.isEmpty(fkName))) {
column.getConstraints(true).setReferencedTableName(relationshipModel.getTableName())
.setReferencedColumnNames(sub.getRefFieldName());
}
}
if(!fieldModel.isPhysicalField())
poSchema.addTransient(column.setComputed(true));
else
poSchema.addColumn(column);
order++;
}
if(entityModel.getDataSets()!=null)
{
entityModel.getDataSets().forEach(dataSet->{
if(dataSet.getDatasetId().startsWith(entityModel.getEntityName().toLowerCase()+"-")&&dataSet.getDatasetId().endsWith(dataSourceType))
{
POSchema.Segment segment=new POSchema.Segment().setName(dataSet.getDatasetId()).setVendorProvider(dataSourceType).setBody(dataSet.getDsCode());
if(!StringUtils.isEmpty(dataSet.getDsModel()))
segment.setFormat(dataSet.getDsModel());
poSchema.addSegment(segment);
}
else if(!dataSet.getDatasetId().startsWith(entityModel.getEntityName().toLowerCase()+"-"))
{
POSchema.Segment segment=new POSchema.Segment().setName(dataSet.getCodeName()).setVendorProvider(dataSourceType).setBody(dataSet.getDsCode());
if(!StringUtils.isEmpty(dataSet.getDsModel()))
segment.setFormat(dataSet.getDsModel());
poSchema.addSegment(segment);
}
});
}
return poSchema;
}
}
package com.ibizlab.codegen;
\ No newline at end of file
package com.ibizlab.codegen.templating;
import com.ibizlab.codegen.TemplateManager;
import com.ibizlab.codegen.api.TemplatePathLocator;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.net.URL;
/**
* Locates generator-agnostic templates from a common built-in location.
*/
public class CommonTemplateContentLocator implements TemplatePathLocator {
private String resourceLocation = "_common";
/**
* Constructs a new instance of {@link CommonTemplateContentLocator} defaulting to _common resource location.
*/
public CommonTemplateContentLocator() {
}
/**
* Constructs a new instance of {@link CommonTemplateContentLocator} for a targeted common location.
*
* @param resourceLocation A custom common file location.
*/
public CommonTemplateContentLocator(String resourceLocation) {
this.resourceLocation = resourceLocation;
}
/**
* Get the full path to a relative template file.
*
* @param relativeTemplateFile Template file
* @return String Full template file path
*/
@Override
public String getFullTemplatePath(String relativeTemplateFile) {
if (StringUtils.isNotEmpty(relativeTemplateFile)) {
String loc = this.resourceLocation + File.separator + relativeTemplateFile;
URL url = this.getClass().getClassLoader().getResource(TemplateManager.getCPResourcePath(loc));
if (url != null) {
return loc;
}
}
return null;
}
}
package com.ibizlab.codegen.templating;
import com.ibizlab.codegen.CodegenConfig;
import com.ibizlab.codegen.TemplateManager;
import com.ibizlab.codegen.api.TemplatePathLocator;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.nio.file.Paths;
/**
* Locates templates according to {@link CodegenConfig} settings.
*/
public class GeneratorTemplateContentLocator implements TemplatePathLocator {
private final CodegenConfig codegenConfig;
/**
* Constructs a new instance of {@link GeneratorTemplateContentLocator} for the provided {@link CodegenConfig}
*
* @param codegenConfig A generator's configuration used for determining template file location.
*/
public GeneratorTemplateContentLocator(CodegenConfig codegenConfig) {
this.codegenConfig = codegenConfig;
}
private String buildLibraryFilePath(String dir, String library, String file) {
return Paths.get(dir, "libraries", library, file).normalize().toString();
}
/**
* Determines whether an embedded file with the specified name exists.
*
* @param name The name of the file (i.e. relative to resource root)
*
* @return true if file is an embedded resource, false if it does not exist
*/
public boolean embeddedTemplateExists(String name) {
return classpathTemplateExists(name);
}
private boolean classpathTemplateExists(String name) {
return this.getClass().getClassLoader().getResource(TemplateManager.getCPResourcePath(name)) != null;
}
/**
* Get the template file path with template dir prepended, and use the library template if exists.
*
* Precedence:
* 1) (template dir)/libraries/(library)
* 2) (template dir)
* 3) (embedded template dir)/libraries/(library)
* 4) (embedded template dir)
*
* Where "template dir" may be user defined and "embedded template dir" are the built-in templates for the given generator.
*
* @param relativeTemplateFile Template file
* @return String Full template file path
*/
@Override
public String getFullTemplatePath(String relativeTemplateFile) {
CodegenConfig config = this.codegenConfig;
//check the supplied template library folder for the file
final String library = config.getLibrary();
if (StringUtils.isNotEmpty(library)) {
//look for the file in the library subfolder of the supplied template
final String libTemplateFile = buildLibraryFilePath(config.templateDir(), library, relativeTemplateFile);
// looks for user-defined file or classpath
// supports template dir which refers to local file system or custom path in classpath as defined by templateDir
if (new File(libTemplateFile).exists() || classpathTemplateExists(libTemplateFile)) {
return libTemplateFile;
}
}
// check the supplied template main folder for the file
// File.separator is necessary here as the file load is OS-specific
final String template = config.templateDir() + File.separator + relativeTemplateFile;
// looks for user-defined file or classpath
// supports template dir which refers to local file system or custom path in classpath as defined by templateDir
if (new File(template).exists() || classpathTemplateExists(template)) {
return template;
}
//try the embedded template library folder next
if (StringUtils.isNotEmpty(library)) {
final String embeddedLibTemplateFile = buildLibraryFilePath(config.embeddedTemplateDir(), library, relativeTemplateFile);
// *only* looks for those files in classpath as defined by embeddedTemplateDir
if (embeddedTemplateExists(embeddedLibTemplateFile)) {
// Fall back to the template file embedded/packaged in the JAR file library folder...
return embeddedLibTemplateFile;
}
}
// Fall back to the template file for generator root directory embedded/packaged in the JAR file...
String loc = config.embeddedTemplateDir() + File.separator + relativeTemplateFile;
// *only* looks for those files in classpath as defined by embeddedTemplateDir
if (embeddedTemplateExists(loc)) {
return loc;
}
return null;
}
}
/*
* 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 com.ibizlab.codegen.templating;
import com.ibizlab.codegen.api.TemplatingEngineAdapter;
import com.ibizlab.codegen.api.TemplatingExecutor;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.Map;
public class MustacheEngineAdapter implements TemplatingEngineAdapter {
private final Logger LOGGER = LoggerFactory.getLogger(TemplatingEngineAdapter.class);
/**
* 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 "mustache";
}
private final String[] extensions = {"mustache"};
Mustache.Compiler compiler = Mustache.compiler();
/**
* Compiles a template into a string
*
* @param executor From where we can fetch the templates content (e.g. an instance of DefaultGenerator)
* @param bundle The map of values to pass to the template
* @param templateFile The name of the template (e.g. model.mustache )
* @return the processed template result
* @throws IOException an error occurred in the template processing
*/
@Override
public String compileTemplate(TemplatingExecutor executor, Map<String, Object> bundle, String templateFile) throws IOException {
Template tmpl = compiler
.withLoader(name -> findTemplate(executor, name))
.defaultValue("")
.compile(executor.getFullTemplateContents(templateFile));
return tmpl.execute(bundle);
}
@SuppressWarnings("java:S108") // catch-all is expected, and is later thrown
public Reader findTemplate(TemplatingExecutor generator, String name) {
for (String extension : extensions) {
final String templateName = name + "." + extension;
try {
return new StringReader(generator.getFullTemplateContents(templateName));
} catch (Exception exception) {
LOGGER.error("Failed to read full template {}, {}", templateName, exception.getMessage());
}
}
throw new TemplateNotFoundException(name);
}
public Mustache.Compiler getCompiler() {
return compiler;
}
public void setCompiler(Mustache.Compiler compiler) {
this.compiler = compiler;
}
@Override
public String[] getFileExtensions() {
return extensions;
}
}
package com.ibizlab.codegen.templating;
/**
* Holds the options relevant to template management and execution.
*/
public class TemplateManagerOptions {
private final boolean minimalUpdate;
private final boolean skipOverwrite;
/**
* Constructs a new instance of {@link TemplateManagerOptions}
*
* @param minimalUpdate See {@link #isMinimalUpdate()}
* @param skipOverwrite See {@link #isSkipOverwrite()}
*/
public TemplateManagerOptions(boolean minimalUpdate, boolean skipOverwrite) {
this.minimalUpdate = minimalUpdate;
this.skipOverwrite = skipOverwrite;
}
/**
* Determines whether the template should minimally update a target file.
*
* A minimal update means the template manager is requested to update a file only if it is newer.
*
* This option avoids "touching" a file and causing the last modification time (mtime) to change.
*
* @return true to prefer updating only changed files, false to disable that suggestion
*/
public boolean isMinimalUpdate() {
return minimalUpdate;
}
/**
* Determines whether the template manager should avoid overwriting an existing file.
*
* This differs from requesting {@link #isMinimalUpdate()} which evaluates contents, while this option only
* evaluates whether the file exists.
*
* @return true to avoid overwriting existing files (where supported), false to disable that suggestion.
*/
public boolean isSkipOverwrite() {
return skipOverwrite;
}
}
package com.ibizlab.codegen.templating;
public class TemplateNotFoundException extends RuntimeException {
/**
* Constructs a new runtime exception with {@code null} as its
* detail message. The cause is not initialized, and may subsequently be
* initialized by a call to {@link #initCause}.
*/
public TemplateNotFoundException() {
}
/**
* Constructs a new runtime exception with the specified detail message.
* The cause is not initialized, and may subsequently be initialized by a
* call to {@link #initCause}.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
*/
public TemplateNotFoundException(String message) {
super(message);
}
/**
* Constructs a new runtime exception with the specified detail message and
* cause. <p>Note that the detail message associated with
* {@code cause} is <i>not</i> automatically incorporated in
* this runtime exception's detail message.
*
* @param message the detail message (which is saved for later retrieval
* by the {@link #getMessage()} method).
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A <code>null</code> value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public TemplateNotFoundException(String message, Throwable cause) {
super(message, cause);
}
/**
* Constructs a new runtime exception with the specified cause and a
* detail message of <code>(cause==null ? null : cause.toString())</code>
* (which typically contains the class and detail message of
* <code>cause</code>). This constructor is useful for runtime exceptions
* that are little more than wrappers for other throwables.
*
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A <code>null</code> value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public TemplateNotFoundException(Throwable cause) {
super(cause);
}
/**
* Constructs a new runtime exception with the specified detail
* message, cause, suppression enabled or disabled, and writable
* stack trace enabled or disabled.
*
* @param message the detail message.
* @param cause the cause. (A {@code null} value is permitted,
* and indicates that the cause is nonexistent or unknown.)
* @param enableSuppression whether or not suppression is enabled
* or disabled
* @param writableStackTrace whether or not the stack trace should
* be writable
* @since 1.7
*/
public TemplateNotFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.templating.mustache;
import com.ibizlab.codegen.CodegenConfig;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import java.io.IOException;
import java.io.Writer;
import static com.ibizlab.codegen.utils.StringAdvUtils.camelize;
/**
* Converts text in a fragment to camelCase.
*
* Register:
* <pre>
* additionalProperties.put("camelcase", new CamelCaseLambda());
* </pre>
*
* Use:
* <pre>
* {{#camelcase}}{{name}}{{/camelcase}}
* </pre>
*/
public class CamelCaseLambda implements Mustache.Lambda {
private CodegenConfig generator = null;
private Boolean escapeParam = false;
private Boolean lowercaseFirstLetter = true;
public CamelCaseLambda(boolean lowercaseFirstLetter) {
this.lowercaseFirstLetter = lowercaseFirstLetter;
}
public CamelCaseLambda() {}
public CamelCaseLambda generator(final CodegenConfig generator) {
this.generator = generator;
return this;
}
public CamelCaseLambda escapeAsParamName(final Boolean escape) {
this.escapeParam = escape;
return this;
}
@Override
public void execute(Template.Fragment fragment, Writer writer) throws IOException {
String text = camelize(fragment.execute(), lowercaseFirstLetter);
if (generator != null) {
text = generator.sanitizeName(text);
}
writer.write(text);
}
}
package com.ibizlab.codegen.templating.mustache;
import com.google.common.base.CaseFormat;
import com.ibizlab.codegen.CodegenConfig;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import java.io.IOException;
import java.io.Writer;
/**
* Converts text from CaseFormat to another CaseFormat
*
* Register:
* <pre>
* additionalProperties.put("convert", new CaseFormatLambda(LOWER_CAMEL, UPPER_UNDERSCORE));
* </pre>
*
* Use:
* <pre>
* {{#convert}}{{name}}{{/convert}}
* </pre>
*/
public class CaseFormatLambda implements Mustache.Lambda {
private CodegenConfig generator = null;
private CaseFormat initialFormat;
private CaseFormat targetFormat;
public CaseFormatLambda(CaseFormat target, CaseFormat targetFormat) {
this.initialFormat = target;
this.targetFormat = targetFormat;
}
public CaseFormatLambda generator(final CodegenConfig generator) {
this.generator = generator;
return this;
}
@Override
public void execute(Template.Fragment fragment, Writer writer) throws IOException {
String text = initialFormat.converterTo(targetFormat).convert(fragment.execute());
if (generator != null && generator.reservedWords().contains(text)) {
text = generator.escapeReservedWord(text);
}
writer.write(text);
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.templating.mustache;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.io.Writer;
/**
* This naively prepends indention to all lines of a fragment.
* <p>
* Generator authors may add helpers for explicitly adding prefixed spaces which fragments won't be aware of.
* <p>
* Register:
* <pre>
* additionalProperties.put("indent4", new IndentedLambda(4));
* additionalProperties.put("indent8", new IndentedLambda(8));
* </pre>
* <p>
* Use:
* <pre>{@code
* {{#indent4}}{{>template}}{{/indent4}}
* {{#indent8}}{{>other_template}}{{/indent8}}
* }</pre>
*/
public class IndentedLambda implements Mustache.Lambda {
private final int prefixSpaceCount;
private final String prefix;
private int spaceCode;
/**
* Constructs a new instance of {@link IndentedLambda}, with an indent count of 4 spaces
*/
public IndentedLambda() {
this(4, " ", null);
}
/**
* Constructs a new instance of {@link IndentedLambda}, with customized indent count and intention character
*
* @param prefixSpaceCount The number of indented characters to apply as a prefix to a fragment.
* @param indentionCharacter String representation of the character used in the indent (e.g. " ", "\t", ".").
*/
public IndentedLambda(int prefixSpaceCount, String indentionCharacter) {
this(prefixSpaceCount, Character.codePointAt(indentionCharacter, 0), null);
}
/**
* Constructs a new instance of {@link IndentedLambda}, with customized indent count and intention character
*
* @param prefixSpaceCount The number of indented characters to apply as a prefix to a fragment.
* @param indentionCharacter String representation of the character used in the indent (e.g. " ", "\t", ".").
* @param prefix An optional prefix to prepend before the line (useful for multi-line comments).
*/
public IndentedLambda(int prefixSpaceCount, String indentionCharacter, String prefix) {
this(prefixSpaceCount, Character.codePointAt(indentionCharacter, 0), prefix);
}
/**
* Constructs a new instance of {@link IndentedLambda}
*
* @param prefixSpaceCount The number of indented characters to apply as a prefix to a fragment.
* @param indentionCodePoint Code point of the single character used for indentation.
*/
private IndentedLambda(int prefixSpaceCount, int indentionCodePoint) {
this(prefixSpaceCount, indentionCodePoint, null);
}
/**
* Constructs a new instance of {@link IndentedLambda}
*
* @param prefixSpaceCount The number of indented characters to apply as a prefix to a fragment.
* @param indentionCodePoint Code point of the single character used for indentation.
* @param prefix An optional prefix to prepend before the line (useful for multi-line comments).
*/
private IndentedLambda(int prefixSpaceCount, int indentionCodePoint, String prefix) {
if (prefixSpaceCount <= 0) {
throw new IllegalArgumentException("prefixSpaceCount must be greater than 0");
}
if (!Character.isValidCodePoint(indentionCodePoint)) {
throw new IllegalArgumentException("indentionCodePoint is an invalid code point ");
}
this.prefixSpaceCount = prefixSpaceCount;
this.spaceCode = indentionCodePoint;
this.prefix = prefix;
}
@Override
public void execute(Template.Fragment fragment, Writer writer) throws IOException {
String text = fragment.execute();
if (text == null || text.length() == 0) {
return;
}
String prefixedIndention = StringUtils.repeat(new String(Character.toChars(spaceCode)), prefixSpaceCount);
StringBuilder sb = new StringBuilder();
String[] lines = text.split(System.lineSeparator());
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
// Mustache will apply correct indentation to the first line of a template (to match declaration location).
// So, we want to skip the first line.
if (i > 0) {
sb.append(prefixedIndention);
if (prefix != null) sb.append(prefix);
}
sb.append(line);
// We've split on the system's line separator. We don't want to add an additional trailing line.
if (i < lines.length - 1) {
sb.append(System.lineSeparator());
}
}
writer.write(sb.toString());
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.templating.mustache;
import com.ibizlab.codegen.CodegenConfig;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import java.io.IOException;
import java.io.Writer;
/**
* Split text by 2 spaces and then join the strings with ", "
*
* Register:
* <pre>
* additionalProperties.put("joinWithComma", new JoinWithCommaLambda());
* </pre>
*
* Use:
* <pre>
* {{#joinWithComma}}{{name}}{{/joinWithComma}}
* </pre>
*/
public class JoinWithCommaLambda implements Mustache.Lambda {
private CodegenConfig generator = null;
public JoinWithCommaLambda() {
}
public JoinWithCommaLambda generator(final CodegenConfig generator) {
this.generator = generator;
return this;
}
@Override
public void execute(Template.Fragment fragment, Writer writer) throws IOException {
String[] substr = fragment.execute().trim().split(" ");
writer.write(String.join(", ", substr));
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.templating.mustache;
import com.ibizlab.codegen.CodegenConfig;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import java.io.IOException;
import java.io.Writer;
import java.util.Locale;
/**
* Converts text in a fragment to lowercase.
*
* Register:
* <pre>
* additionalProperties.put("lowercase", new LowercaseLambda());
* </pre>
*
* Use:
* <pre>
* {{#lowercase}}{{httpMethod}}{{/lowercase}}
* </pre>
*/
public class LowercaseLambda implements Mustache.Lambda {
private CodegenConfig generator = null;
public LowercaseLambda() {
}
public LowercaseLambda generator(final CodegenConfig generator) {
this.generator = generator;
return this;
}
@Override
public void execute(Template.Fragment fragment, Writer writer) throws IOException {
String text = fragment.execute().toLowerCase(Locale.ROOT);
if (generator != null && generator.reservedWords().contains(text)) {
text = generator.escapeReservedWord(text);
}
writer.write(text);
}
}
package com.ibizlab.codegen.templating.mustache;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.Writer;
/**
* Lambda writes current fragment to the output when it is different than
* the previous fragment.
*
* Register:
* <pre>
* additionalProperties.put("onchange", new OnChangeLambda());
* </pre>
*
* Use:
* <pre>
* {{#onchange}}{{name}}{{/onchange}}
* </pre>
*/
public class OnChangeLambda implements Mustache.Lambda {
private final Logger LOGGER = LoggerFactory.getLogger(OnChangeLambda.class);
private String lastVal = null;
@Override
public void execute(Template.Fragment frag, Writer out) throws IOException {
String curVal = frag.execute();
LOGGER.debug("[lastVal={}, curVal={}]", lastVal, curVal);
if (curVal != null && !curVal.equals(lastVal)) {
out.write(curVal);
lastVal = curVal;
}
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.templating.mustache;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template.Fragment;
import java.io.IOException;
import java.io.Writer;
/**
* Replaces duplicate whitespace characters in a fragment with single space.
*
* Register:
* <pre>
* additionalProperties.put("lambdaPrefixWithHash", new PrefixWithHashLambda());
* </pre>
*
* Use:
* <pre>
* {{#lambdaPrefixWithHash}}{{name}}{{/lambdaPrefixWithHash}}
* </pre>
*/
public class PrefixWithHashLambda implements Mustache.Lambda {
private static final String WITH_HASH = "\n#";
private static final String NEWLINE_REGEX = "\\R";
@Override
public void execute(Fragment fragment, Writer writer) throws IOException {
writer.write(fragment.execute().replaceAll(NEWLINE_REGEX, WITH_HASH));
}
}
/*
* Copyright 2018 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 com.ibizlab.codegen.templating.mustache;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import java.io.IOException;
import java.io.Writer;
import static com.ibizlab.codegen.utils.StringAdvUtils.underscore;
/**
* Converts text in a fragment to snake case.
*
* Register:
* <pre>
* additionalProperties.put("snakecase", new SnakecaseLambda());
* </pre>
*
* Use:
* <pre>
* {{#snakecase}}{{summary}}{{/snakecase}}
* </pre>
*/
public class SnakecaseLambda implements Mustache.Lambda {
@Override
public void execute(Template.Fragment fragment, Writer writer) throws IOException {
writer.write(underscore(fragment.execute()));
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.templating.mustache;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template.Fragment;
import java.io.IOException;
import java.io.Writer;
import java.util.Locale;
/**
* Splits long fragments into smaller strings and uses a StringBuilder to merge
* them back.
*
* Register:
*
* <pre>
* additionalProperties.put("lambdaSplitString", new SplitStringLambda());
* </pre>
*
* Use:
*
* <pre>
* {{#lambdaSplitString}}{{summary}}{{/lambdaSplitString}}
* </pre>
*/
public class SplitStringLambda implements Mustache.Lambda {
private static final int DEFAULT_MAX_LENGTH = 65535;
private static final String SPLIT_INIT = "new StringBuilder(%d)";
private static final String SPLIT_PART = ".append(\"%s\")";
private static final String SPLIT_SUFFIX = ".toString()";
private final int maxLength;
public SplitStringLambda() {
this(DEFAULT_MAX_LENGTH);
}
public SplitStringLambda(int maxLength) {
this.maxLength = maxLength;
}
@Override
public void execute(Fragment fragment, Writer writer) throws IOException {
String input = fragment.execute();
int inputLength = input.length();
StringBuilder builder = new StringBuilder();
if (inputLength > maxLength) {
// Initialize a StringBuilder
builder.append(String.format(Locale.ROOT, SPLIT_INIT, inputLength));
int currentPosition = 0;
int currentStringLength = 0;
char currentLastChar = '\\';
// Split input into parts of at most maxLength and not ending with an escape character
// Append each part to the StringBuilder
while (currentPosition + maxLength < input.length()) {
currentStringLength = maxLength;
currentLastChar = input.charAt(currentPosition + currentStringLength - 1);
if (currentLastChar == '\\') {
--currentStringLength;
}
builder.append(String.format(Locale.ROOT, SPLIT_PART, input.substring(currentPosition, currentPosition + currentStringLength)));
currentPosition += currentStringLength;
}
// Append last part if necessary
if (currentPosition < input.length()) {
builder.append(String.format(Locale.ROOT, SPLIT_PART, input.substring(currentPosition)));
}
// Close the builder and merge everything back to a string
builder.append(SPLIT_SUFFIX);
} else {
builder.append(String.format(Locale.ROOT, "\"%s\"", input));
}
writer.write(builder.toString());
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.templating.mustache;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import java.io.IOException;
import java.io.Writer;
import java.util.Locale;
/**
* Converts text in a fragment to title case.
*
* Register:
* <pre>
* additionalProperties.put("titlecase", new TitlecaseLambda());
* </pre>
*
* Use:
* <pre>
* {{#titlecase}}{{classname}}{{/titlecase}}
* </pre>
*/
public class TitlecaseLambda implements Mustache.Lambda {
private String delimiter;
/**
* Constructs a new instance of {@link TitlecaseLambda}, which will convert all text
* in a space delimited string to title-case.
*/
public TitlecaseLambda() {
this(" ");
}
/**
* Constructs a new instance of {@link TitlecaseLambda}, splitting on the specified
* delimiter and converting each word to title-case.
*
* NOTE: passing {@code null} results in a title-casing the first word only.
*
* @param delimiter Provided to allow an override for the default space delimiter.
*/
public TitlecaseLambda(String delimiter) {
this.delimiter = delimiter;
}
private String titleCase(final String input) {
return input.substring(0, 1).toUpperCase(Locale.ROOT) + input.substring(1);
}
@Override
public void execute(Template.Fragment fragment, Writer writer) throws IOException {
String text = fragment.execute();
if (delimiter == null) {
writer.write(titleCase(text));
return;
}
// Split accepts regex. \Q and \E wrap the delimiter to create a literal regex,
// so things like "." and "|" aren't treated as their regex equivalents.
String[] parts = text.split("\\Q" + delimiter + "\\E");
for (int i = 0; i < parts.length; i++) {
String part = parts[i];
writer.write(titleCase(part));
if (i != parts.length - 1) {
writer.write(delimiter);
}
}
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.templating.mustache;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template.Fragment;
import java.io.IOException;
import java.io.Writer;
/**
* Replaces duplicate whitespace characters in a fragment with single space.
*
* Register:
* <pre>
* additionalProperties.put("lambdaTrimWhitespace", new TrimWhitespaceLambda());
* </pre>
*
* Use:
* <pre>
* {{#lambdaTrimWhitespace}}{{name}}{{/lambdaTrimWhitespace}}
* </pre>
*/
public class TrimWhitespaceLambda implements Mustache.Lambda {
private static final String SINGLE_SPACE = " ";
private static final String WHITESPACE_REGEX = "\\s+";
@Override
public void execute(Fragment fragment, Writer writer) throws IOException {
writer.write(fragment.execute().replaceAll(WHITESPACE_REGEX, SINGLE_SPACE));
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.templating.mustache;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import java.io.IOException;
import java.io.Writer;
import java.util.Locale;
/**
* Converts text in a fragment to uppercase.
*
* Register:
* <pre>
* additionalProperties.put("uppercase", new UppercaseLambda());
* </pre>
*
* Use:
* <pre>
* {{#uppercase}}{{summary}}{{/uppercase}}
* </pre>
*/
public class UppercaseLambda implements Mustache.Lambda {
@Override
public void execute(Template.Fragment fragment, Writer writer) throws IOException {
String text = fragment.execute();
writer.write(text.toUpperCase(Locale.ROOT));
}
}
package com.ibizlab.codegen.utils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
public class DataObject {
final static public DateFormat datetimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
final static public DateFormat datetimeFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm");
final static public DateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd");
final static public String getStringValue(Object objValue, String strDefault) {
if (objValue == null) {
return strDefault;
}
if (objValue instanceof String) {
return (String) objValue;
}
if (objValue instanceof java.sql.Timestamp||objValue instanceof java.sql.Date||objValue instanceof java.util.Date) {
String rt=datetimeFormat.format(objValue);
if(rt.endsWith(" 00:00:00")) {
rt=dayFormat.format(objValue);
}
return rt;
}
if(objValue instanceof BigDecimal)
{
return getBigDecimalValue(objValue,BigDecimal.ZERO).toString();
}
return objValue.toString();
}
public static <T> Object objectValueOf(Class<T> type,Object fieldValue) {
if(fieldValue==null) {
return null;
}
Object resultValue=fieldValue;
String targetType=type.getSimpleName();
if(targetType.equals(fieldValue.getClass().getSimpleName())){
return resultValue;
}
if(targetType.equals("Boolean")){
resultValue=getBooleanValue(fieldValue,false);
}
else if(targetType.equals("Character")){
resultValue=getCharacterValue(fieldValue,null);
}
else if(targetType.equals("Byte")){
resultValue=getBinaryValue(fieldValue,null);
}
else if(targetType.equals("Short")){
resultValue=Short.valueOf(fieldValue.toString());
}
else if(targetType.equals("Integer")){
resultValue= getIntegerValue(fieldValue,null);
}
else if(targetType.equals("Long")){
resultValue=getLongValue(fieldValue,null);
}
else if(targetType.equals("Float")){
resultValue= getFloatValue(fieldValue,null);
}
else if(targetType.equals("Double")){
resultValue= getDoubleValue(fieldValue,null);
}
else if(targetType.equals("BigDecimal")){
resultValue= getBigDecimalValue(fieldValue,null);
}
else if(targetType.equals("BigInteger")){
resultValue= getBigIntegerValue(fieldValue,null);
}
else if(targetType.equals("Timestamp")){
resultValue= getTimestampValue(fieldValue,null);
}
else if(targetType.equals("String")) {
resultValue= getStringValue(fieldValue,null);
}
if(resultValue==null) {
return null;
}
return resultValue;
}
public static <T> T valueOf(Class<T> type,Object fieldValue) {
return (T)objectValueOf(type,fieldValue);
}
final static public JSONObject getJSONObjectValue(Object objValue, JSONObject jDefault) {
if (objValue == null) {
return jDefault;
}
if(objValue instanceof JSONObject) {
return (JSONObject)objValue;
}
String strValue = objValue.toString();
try {
return JSONObject.parseObject(strValue);
}
catch (Exception ex)
{
return jDefault;
}
}
final static public JSONArray getJSONArrayValue(Object objValue, JSONArray jDefault) {
if (objValue == null) {
return jDefault;
}
if(objValue instanceof JSONArray) {
return (JSONArray)objValue;
}
String strValue = objValue.toString();
try {
return JSONArray.parseArray(strValue);
}
catch (Exception ex)
{
return jDefault;
}
}
final static public List<String> getListValue(Object objValue) {
if (objValue == null) {
return new ArrayList<String>();
}
JSONArray arr=(getJSONArrayValue(objValue,null));
if(arr!=null)
{
List<String> chk1=new ArrayList<>();
for(int i=0;i<arr.size();i++)
{
if(arr.get(i) instanceof String) {
chk1.add(arr.getString(i));
}
}
return chk1;
}
else
{
return new ArrayList<String>();
}
}
final static public Boolean getBooleanValue(Object objValue,Boolean bDefault) {
if (objValue == null) {
return bDefault;
}
if (objValue instanceof Boolean) {
return (Boolean) objValue;
}
return DataObject.getStringValue(objValue,"").equalsIgnoreCase("true")||objValue.toString().equals("1")||objValue.toString().equalsIgnoreCase("y");
}
final static public char[] getCharacterValue(Object objValue,char[] cDefault) {
if (objValue == null) {
return cDefault;
}
return objValue.toString().toCharArray();
}
final static public Double getDoubleValue(Object objValue,Double dDefault) {
if (objValue == null) {
return dDefault;
}
if (objValue instanceof Double) {
return (Double) objValue;
}
String strValue = objValue.toString();
if (StringUtils.isEmpty(strValue)) {
return null;
}
strValue = strValue.replace(",", "");
return Double.parseDouble(strValue);
}
final static public Integer getIntegerValue( Object objValue, Integer nDefault) {
if (objValue == null) {
return nDefault;
}
if(objValue instanceof Integer) {
return (Integer)objValue;
}
if (objValue instanceof Double) {
return ((Double) objValue).intValue();
}
if (objValue instanceof BigDecimal) {
return ((BigDecimal) objValue).intValue();
}
String strValue = objValue.toString();
if(StringUtils.isEmpty(strValue)) {
return nDefault;
}
strValue = strValue.replace(",", "");
return Integer.parseInt(strValue);
}
final static public Float getFloatValue( Object objValue, Float fDefault) {
if (objValue == null) {
return fDefault;
}
try {
if(objValue instanceof Float) {
return (Float)objValue;
}
String strValue = objValue.toString();
if(StringUtils.isEmpty(strValue)) {
return fDefault;
}
strValue = strValue.replace(",", "");
return Float.parseFloat(strValue);
} catch (Exception ex) {
return fDefault;
}
}
final static public BigDecimal getBigDecimalValue( Object objValue, BigDecimal fDefault) {
if (objValue == null) {
return fDefault;
}
try {
if(objValue instanceof BigDecimal){
return ((BigDecimal)(objValue)).stripTrailingZeros();
}
if(objValue instanceof Double){
return BigDecimal.valueOf((Double)objValue).stripTrailingZeros();
}
if(objValue instanceof Long){
return BigDecimal.valueOf((Long)objValue).stripTrailingZeros();
}
String strValue = objValue.toString();
if(StringUtils.isEmpty(strValue)) {
return fDefault;
}
strValue = strValue.replace(",", "");
return BigDecimal.valueOf(Double.parseDouble(strValue)).stripTrailingZeros();
} catch (Exception ex) {
return fDefault;
}
}
final static public BigInteger getBigIntegerValue( Object objValue, BigInteger fDefault) {
if (objValue == null) {
return fDefault;
}
try {
if(objValue instanceof BigInteger){
return (BigInteger)(objValue);
}
else {
Long l=getLongValue(objValue,null);
if(l!=null) {
return BigInteger.valueOf(l);
}
}
} catch (Exception ex) {
}
return fDefault;
}
final static public Long getLongValue( Object objValue, Long nDefault) {
if (objValue == null) {
return nDefault;
}
try {
if (objValue instanceof Long) return (Long) objValue;
if (objValue instanceof Integer) {
return ((Integer) objValue).longValue();
}
if (objValue instanceof Double) {
return ((Double) objValue).longValue();
}
if (objValue instanceof BigDecimal) {
return ((BigDecimal) objValue).longValue();
}
String strValue = objValue.toString();
if(StringUtils.isEmpty(strValue)) {
return nDefault;
}
strValue = strValue.replace(",", "");
return Long.parseLong(strValue);
} catch (Exception ex) {
return nDefault;
}
}
final static public byte[] getBinaryValue(Object objValue, byte[] def) {
if (objValue == null) {
return def;
}
if(objValue instanceof byte[]){
return (byte[])objValue;
}
if (objValue instanceof String){
return Base64.getDecoder().decode((String) objValue);
}
return def;
}
/**
* 转换对象值到时间值
*
* @param objValue
* @return
* @
*/
final static public java.sql.Timestamp getTimestampValue(Object objValue,java.sql.Timestamp tDefault) {
if (objValue == null) {
return tDefault;
}
if (objValue instanceof java.sql.Timestamp) {
java.sql.Timestamp ti = (java.sql.Timestamp) objValue;
return ti;
}
if (objValue instanceof java.sql.Date) {
java.sql.Date date = (java.sql.Date) objValue;
return new java.sql.Timestamp(date.getTime());
}
if (objValue instanceof java.util.Date) {
java.util.Date date = (java.util.Date) objValue;
return new java.sql.Timestamp(date.getTime());
}
if (objValue instanceof String) {
String strValue = (String) objValue;
strValue = strValue.trim();
if (StringUtils.isEmpty(strValue)) {
return null;
}
try {
java.util.Date date = parse((String) objValue);
return new java.sql.Timestamp(date.getTime());
}
catch (Exception ex)
{
return tDefault;
}
}
if(objValue instanceof Long)
{
Long lValue = (Long)objValue;
return new java.sql.Timestamp(lValue);
}
return tDefault;
}
public static Object testDateTime(String strInput) throws Exception{
return testDateTime(strInput, null);
}
/**
* 转换文本值到日期时间
*
* @param strInput
* @param timeZone
* @return
* @
*/
public static Object testDateTime(String strInput, TimeZone timeZone) throws Exception{
if (StringUtils.isEmpty(strInput)) {
return null;
}
Date dtDate = parse(strInput, timeZone);
java.sql.Timestamp retDate = new java.sql.Timestamp(dtDate.getTime());
return retDate;
}
/**
* 转换字符串到时间对象
*
* @param strTimeString
* @return
* @throws ParseException
* @
*/
public static Date parse(String strTimeString) throws ParseException, Exception {
return parse(strTimeString, null);
}
/**
* 分析时间串
*
* @param strTimeString MM/dd/yy yy-MM-dd HH:mm:ss 格式
* @param timeZone
* @return
* @throws ParseException
* @
*/
public static Date parse(String strTimeString, TimeZone timeZone) throws ParseException, Exception {
strTimeString = strTimeString.trim();
if(StringUtils.isEmpty(strTimeString)){
throw new Exception("unknown date(time) string");
}
if(strTimeString.indexOf("Z")!=-1){
//有时区
String[] parts = strTimeString.split("[Z]");
if(parts.length>=1){
strTimeString = parts[0];
}
if(parts.length>=2){
if(timeZone == null){
if(!StringUtils.isEmpty(parts[1])){
timeZone = TimeZone.getTimeZone(parts[1]);
}
}
}
}
// 判断是长数据还是短数据
String strPart[] = null;
if(strTimeString.indexOf("T")!=-1){
strPart = strTimeString.split("[T]");
}
else{
strPart = strTimeString.split(" ");
}
if (strPart.length == 2) {
// 两个部分
String strDate = "";
String strTime = "";
if (strPart[0].indexOf(":") != -1) {
strTime = strPart[0];
strDate = strPart[1];
} else {
strTime = strPart[1];
strDate = strPart[0];
}
strDate = strDate.trim();
strTime = strTime.trim();
strDate = getFormatDateString(strDate);
strTime = getFormatTimeString(strTime);
DateFormat dtFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
if (timeZone != null) {
dtFormat.setTimeZone(timeZone);
}
return dtFormat.parse(strDate + " " + strTime);
} else {
// 一个部分
if (strTimeString.indexOf(":") != -1) {
// 时间
strTimeString = getFormatTimeString(strTimeString);
DateFormat dtFormat = new SimpleDateFormat("HH:mm:ss");
if (timeZone != null) {
dtFormat.setTimeZone(timeZone);
}
return dtFormat.parse(strTimeString);
} else {
// 作为日期处理
strTimeString = getFormatDateString(strTimeString);
DateFormat dtFormat = new SimpleDateFormat("yyyy-MM-dd");
if (timeZone != null) {
dtFormat.setTimeZone(timeZone);
}
return dtFormat.parse(strTimeString);
}
}
}
/**
* 获取时间格式化串
*
* @param strOrigin
* @return
*/
private static String getFormatTimeString(String strOrigin) {
int nDotPos = strOrigin.indexOf(".");
if (nDotPos != -1) {
strOrigin = strOrigin.substring(0, nDotPos);
}
Object Time[] = new Object[3];
Time[0] = 0;
Time[1] = 0;
Time[2] = 0;
String timepart[] = strOrigin.split(":");
int nTimePartLength = timepart.length;
if (nTimePartLength > 3) {
nTimePartLength = 3;
}
for (int i = 0; i < nTimePartLength; i++) {
Time[i] = Integer.parseInt(timepart[i]);
}
return String.format("%1$02d:%2$02d:%3$02d", Time);
}
/**
* 获取时日期格式化串
*
* @param strOrigin
* @return
* @
*/
private static String getFormatDateString(String strOrigin) throws Exception{
return getFormatDateString(strOrigin, true);
}
/**
* 获取时日期格式化串
*
* @param strOrigin
* @param bAdv
* @return
* @
*/
private static String getFormatDateString(String strOrigin, boolean bAdv) throws Exception{
Object Date[] = new Object[3];
Date[0] = 1970;
Date[1] = 1;
Date[2] = 1;
if (strOrigin.indexOf("-") != -1) {
String datePart[] = strOrigin.split("-");
if (datePart.length >= 1) {
Date[0] = Integer.parseInt(datePart[0]);
}
if (datePart.length >= 2) {
Date[1] = Integer.parseInt(datePart[1]);
}
if (datePart.length >= 3) {
Date[2] = Integer.parseInt(datePart[2]);
}
}
else if (strOrigin.indexOf("/") != -1) {
String datePart[] = strOrigin.split("/");
if (datePart.length >= 1) {
Date[1] = Integer.parseInt(datePart[0]);
}
if (datePart.length >= 2) {
Date[2] = Integer.parseInt(datePart[1]);
}
if (datePart.length >= 3) {
Date[0] = Integer.parseInt(datePart[2]);
}
} else {
if (bAdv) {
strOrigin = strOrigin.replace(".", "-");
strOrigin = strOrigin.replace("日", "");
strOrigin = strOrigin.replace("天", "");
strOrigin = strOrigin.replace("年", "-");
strOrigin = strOrigin.replace("月", "-");
return getFormatDateString(strOrigin, false);
} else
throw new Exception("无法识别的时间字符串,"+strOrigin);
}
return String.format("%1$04d-%2$02d-%3$02d", Date);
}
public static Timestamp getBeginDate()
{
Calendar cl=Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
cl.set(1900,1,1);
return new Timestamp(cl.getTime().getTime());
}
public static Timestamp getEndDate()
{
Calendar cl=Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
cl.set(2100,12,31,23,59,59);
return new Timestamp(cl.getTime().getTime());
}
public static Timestamp getNow()
{
Calendar cl=Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
return new Timestamp(cl.getTime().getTime());
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.utils;
public class ImplementationVersion {
public static String read() {
// Assumes this version is required at runtime. This could be modified to use a properties file like the CLI.
String compiledVersion = ImplementationVersion.class.getPackage().getImplementationVersion();
if (compiledVersion != null) {
return compiledVersion;
}
// When running non-JARed class within an IDE the implementation version is not available, so we provide a means
// to set it externally via a system property so that generated artefacts contain the correct version.
return System.getProperty("openapitools.implementation.version", "unset");
}
}
package com.ibizlab.codegen.utils;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
*
* 单复数转换类
* 2018年12月30日
*/
public class Inflector {
private static final Pattern UNDERSCORE_PATTERN_1 = Pattern.compile("([A-Z]+)([A-Z][a-z])");
private static final Pattern UNDERSCORE_PATTERN_2 = Pattern.compile("([a-z\\d])([A-Z])");
private static List<RuleAndReplacement> plurals = new ArrayList<RuleAndReplacement>();
private static List<RuleAndReplacement> singulars = new ArrayList<RuleAndReplacement>();
private static List<String> uncountables = new ArrayList<String>();
private static Inflector instance;
private Inflector() {
initialize();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
// 单数转复数
System.out.println(Inflector.getInstance().pluralize("water"));
System.out.println(Inflector.getInstance().pluralize("box"));
System.out.println(Inflector.getInstance().pluralize("tomato"));
// 复数转单数
System.out.println(Inflector.getInstance().singularize("apples"));
}
private void initialize() {
plural("$", "s");
plural("s$", "s");
plural("(ax|test)is$", "$1es");
plural("(octop|vir)us$", "$1i");
plural("(alias|status)$", "$1es");
plural("(bu)s$", "$1es");
plural("(buffal|tomat)o$", "$1oes");
plural("([ti])um$", "$1a");
plural("sis$", "ses");
plural("(?:([^f])fe|([lr])f)$", "$1$2ves");
plural("(hive)$", "$1s");
plural("([^aeiouy]|qu)y$", "$1ies");
plural("([^aeiouy]|qu)ies$", "$1y");
plural("(x|ch|ss|sh)$", "$1es");
plural("(matr|vert|ind)ix|ex$", "$1ices");
plural("([m|l])ouse$", "$1ice");
plural("(ox)$", "$1es");
plural("(quiz)$", "$1zes");
singular("s$", "");
singular("(n)ews$", "$1ews");
singular("([ti])a$", "$1um");
singular("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis");
singular("(^analy)ses$", "$1sis");
singular("([^f])ves$", "$1fe");
singular("(hive)s$", "$1");
singular("(tive)s$", "$1");
singular("([lr])ves$", "$1f");
singular("([^aeiouy]|qu)ies$", "$1y");
singular("(s)eries$", "$1eries");
singular("(m)ovies$", "$1ovie");
singular("(x|ch|ss|sh)es$", "$1");
singular("([m|l])ice$", "$1ouse");
singular("(bus)es$", "$1");
singular("(o)es$", "$1");
singular("(shoe)s$", "$1");
singular("(cris|ax|test)es$", "$1is");
singular("([octop|vir])i$", "$1us");
singular("(alias|status)es$", "$1");
singular("^(ox)es", "$1");
singular("(vert|ind)ices$", "$1ex");
singular("(matr)ices$", "$1ix");
singular("(quiz)zes$", "$1");
irregular("person", "people");
irregular("man", "men");
irregular("child", "children");
irregular("sex", "sexes");
irregular("move", "moves");
uncountable(new String[] { "equipment", "information", "rice", "money", "species", "series", "fish", "sheep" });
}
public static Inflector getInstance() {
if (instance == null) {
instance = new Inflector();
}
return instance;
}
public String underscore(String camelCasedWord) {
String underscoredWord = UNDERSCORE_PATTERN_1.matcher(camelCasedWord).replaceAll("$1_$2");
underscoredWord = UNDERSCORE_PATTERN_2.matcher(underscoredWord).replaceAll("$1_$2");
underscoredWord = underscoredWord.replace('-', '_').toLowerCase();
return underscoredWord;
}
public String pluralize(String word) {
if (uncountables.contains(word.toLowerCase())) {
return word;
}
return replaceWithFirstRule(word, plurals);
}
public String singularize(String word) {
if (uncountables.contains(word.toLowerCase())) {
return word;
}
return replaceWithFirstRule(word, singulars);
}
private String replaceWithFirstRule(String word, List<RuleAndReplacement> ruleAndReplacements) {
for (RuleAndReplacement rar : ruleAndReplacements) {
String rule = rar.getRule();
String replacement = rar.getReplacement();
// Return if we find a match.
Matcher matcher = Pattern.compile(rule, Pattern.CASE_INSENSITIVE).matcher(word);
if (matcher.find()) {
return matcher.replaceAll(replacement);
}
}
return word;
}
public String tableize(String className) {
return pluralize(underscore(className));
}
public String tableize(Class<?> klass) {
String className = klass.getName().replace(klass.getPackage().getName() + ".", "");
return tableize(className);
}
public static void plural(String rule, String replacement) {
plurals.add(0, new RuleAndReplacement(rule, replacement));
}
public static void singular(String rule, String replacement) {
singulars.add(0, new RuleAndReplacement(rule, replacement));
}
public static void irregular(String singular, String plural) {
plural(singular, plural);
singular(plural, singular);
}
public static void uncountable(String... words) {
for (String word : words) {
uncountables.add(word);
}
}
}
class RuleAndReplacement {
private String rule;
private String replacement;
public RuleAndReplacement(String rule, String replacement) {
this.rule = rule;
this.replacement = replacement;
}
public String getReplacement() {
return replacement;
}
public void setReplacement(String replacement) {
this.replacement = replacement;
}
public String getRule() {
return rule;
}
public void setRule(String rule) {
this.rule = rule;
}
}
\ No newline at end of file
/*
* 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 com.ibizlab.codegen.utils;
import com.fasterxml.jackson.core.JsonPointer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
/**
* An interface for querying and mutating a JSON object graph. Clients indicate the location within the graph at which a
* value is to be read or written using a <a href="https://tools.ietf.org/html/rfc6901">JSON Pointer</a> as either a
* string or a <code>JsonPointer</code> instance. The latter is more efficient for repeated access to the same location.
* For the <code>set(ptr|path, value)</code> and <code>getXxx(ptr|path, defaultValue)</code>methods, the cache
* automatically creates missing container elements in the path as either object or array nodes according to whether the
* corresponding path segment is a property name or an integer index respectively, and creates the leaf element as a
* JSON value node of the appropriate type. Existing tree elements identified by a JSON pointer must match the pointer
* segments by type; that is, an existing parent of an integer path segment <b>must</b> be an array node and existing
* parent of a property name path segment <b>must</b> be an object node: if this condition is not met, the method throws
* a {@linkplain CacheException}. Note that it is possible to store the same object at multiple locations
* within the tree (thus converting the tree to a <i>graph</i>), in which case the same object may be retrieved using
* any of the corresponding paths. However, this shared object becomes multiple independent objects when serialised to
* JSON and if subsequently loaded into a cache instance. Such graphs <b>must</b> be acyclic: storing a cyclic graph in
* the tree will cause a stack overflow when the cache is saved. Instances are not guaranteed threadsafe and require
* external synchronisation if mutator methods may be called concurrently from multiple threads. Sparse arrays are not
* supported - all array elements have a value, even if it is null.
* <p>
* <em>N.B. some <code>getXxx()</code> methods can return mutable objects, mutations to which will be unobserved by the
* cache instance, thus compromising the reliability of the <code>flush*()</code> methods. Callers relying on these
* methods should either not mutate such objects or they should call the appropriate <code>set()</code> method
* afterwards to ensure that the cache's 'modified' flag is set.</em>
* </p>
*
* @author Adrian Price, TIBCO Software Inc.
* @since 4.0.0
*/
public interface JsonCache {
/**
* Exception thrown by cache operations. Not intended to be created by client code.
*/
static class CacheException extends Exception {
private static final long serialVersionUID = -1215367978375557620L;
CacheException(String message) {
super(message);
}
CacheException(Throwable cause) {
super(cause);
}
}
/**
* A factory for creating JSON cache root instances.
*/
interface Factory {
/**
* The singleton factory instance.
*/
Factory instance = JsonCacheImpl.FactoryImpl.instance;
/**
* Returns a new cache root instance.
*
* @return A new instance.
*/
Root create();
/**
* Returns the singleton cache root instance for the specified key. The same instance is returned every time the
* method is called with the same <code>key</code> value, being lazily created on the first such call.
*
* @param key The instance key.
* @return The singleton instance for <code>key</code>.
*/
Root get(String key);
}
/**
* Load/merge/save/flush functionality implemented by the root of a JSON cache hierarchy.
*/
interface Root extends JsonCache {
/**
* Describes cache behaviour when a load method is called for a cache instance that is already loaded.
*/
enum MergePolicy {
/**
* Calls to <code>load()</code> methods are ignored when the cache is already loaded.
*/
NO_MERGE,
/**
* Recursively merges the incoming tree into the existing tree, retaining existing leaf properties.
*/
MERGE_RECURSIVE,
/**
* Retains existing root properties, ignoring incoming duplicate properties.
*/
KEEP_EXISTING,
/**
* Overwrites existing root properties with incoming duplicate properties.
*/
OVERWRITE_EXISTING
}
/**
* If the cache is dirty, saves the object graph in JSON format to the specified file.
*
* @param file The output file.
* @return The receiver, to allow chaining.
* @throws CacheException if the root node does not exist or if unable to create or write the file.
* @throws NullPointerException if <code>file</code> is <code>null</code>.
* @see #flushOnShutdown(File)
* @see #save(File)
*/
Root flush(File file) throws CacheException;
/**
* If the cache is dirty, saves the object graph in JSON format to the specified stream.
*
* @param out The output stream, which is closed before the method returns.
* @return The receiver, to allow chaining.
* @throws CacheException if the root node does not exist or if unable to create or write the file.
* @throws NullPointerException if <code>out</code> is <code>null</code>.
* @see #flushOnShutdown(OutputStream)
* @see #save(OutputStream)
*/
Root flush(OutputStream out) throws CacheException;
/**
* Makes a best-effort attempt to ensure that the cache gets flushed to a disk file if dirty on shutdown. The
* call has no additional effect if the shutdown hook has already been registered.
*
* @param file The output file.
* @return The receiver, to allow chaining.
* @throws NullPointerException if <code>file</code> is <code>null</code>.
* @see #save(File)
*/
Root flushOnShutdown(File file);
/**
* Makes a best-effort attempt to ensure that the cache gets flushed to an output stream if dirty on shutdown.
* The call has no additional effect if the shutdown hook has already been registered.
*
* @param out The output stream, which is closed after writing it on shutdown.
* @return The receiver, to allow chaining.
* @throws NullPointerException if <code>out</code> is <code>null</code>.
* @see #save(OutputStream)
*/
Root flushOnShutdown(OutputStream out);
/**
* Returns the mapper used for JSON-object marshalling and serialisation operations. Callers may configure the
* mapper to achieve the desired JSON serialisation format.
*
* @return The mapper.
* @see #mapper(ObjectMapper)
*/
ObjectMapper getMapper();
/**
* Returns the merge policy that applies when <code>load()</code> is called on a cache that is already loaded.
* The default is {@link MergePolicy#MERGE_RECURSIVE};
*
* @return The merge policy.
* @see #mergePolicy(MergePolicy)
*/
MergePolicy getMergePolicy();
/**
* Indicates whether the cached has unsaved changes.
*
* @return <code>true</code> if there are unsaved changes.
*/
boolean isDirty();
/**
* Loads the cache from the specified file. If the cache is already loaded, merges the incoming tree according
* to the current {@link #mergePolicy(MergePolicy) merge policy}. The call has no effect if the file does not
* exist.
*
* @param file The JSON file to load.
* @return The receiver, to allow chaining.
* @throws CacheException if the file exists but could not be read or its content is not valid JSON.
* @throws NullPointerException if <code>file</code> is <code>null</code>.
* @see #save(File)
* @see #save(OutputStream)
* @see #unload()
*/
Root load(File file) throws CacheException;
/**
* Loads the cache from the specified stream. If the cache is already loaded, merges the incoming tree according
* to the current {@link #mergePolicy(MergePolicy) merge policy}.
*
* @param in The input stream from which to load, which is closed before the method returns.
* @return The receiver, to allow chaining.
* @throws CacheException if the stream content is not valid JSON.
* @throws NullPointerException if <code>in</code> is <code>null</code>.
* @see #save(File)
* @see #save(OutputStream)
* @see #unload()
*/
Root load(InputStream in) throws CacheException;
/**
* Sets the mapper to use for JSON-object marshalling and serialisation operations.
*
* @param mapper The new mapper.
* @return The receiver, to allow chaining.
* @throws NullPointerException if <code>mapper</code> is <code>null</code>.
* @see #getMapper()
*/
Root mapper(ObjectMapper mapper);
/**
* Sets the merge policy that applies when <code>load()</code> is called for a cache that is already loaded.
*
* @param policy The merge policy.
* @return The receiver, to allow chaining.
* @throws NullPointerException if <code>policy</code> is null.
* @see #getMergePolicy()
*/
Root mergePolicy(MergePolicy policy);
/**
* Saves the object graph in JSON format to the specified file.
*
* @param file The output file.
* @return The receiver, to allow chaining.
* @throws NullPointerException if <code>file</code> is null.
* @throws CacheException if the root node does not exist or if unable to create or write the file.
*/
Root save(File file) throws CacheException;
/**
* Saves the object graph in JSON format to the specified stream.
*
* @param out The output stream, which is closed before the method returns.
* @return The receiver, to allow chaining.
* @throws NullPointerException if <code>out</code> is null.
* @throws CacheException if the root node does not exist or if unable to create or write the file.
*/
Root save(OutputStream out) throws CacheException;
/**
* Unloads the object graph, setting the root node to <code>null</code>.
*
* @return The receiver, to allow chaining.
* @see #load(File)
* @see #load(InputStream)
*/
Root unload();
}
/**
* Adds a <code>BigDecimal</code> to an array. The array is created if it does not already exist.
*
* @param ptr A pointer to the property to set. If the last segment is a positive integer less than the current
* array size, <code>value</code> is inserted at the specified index; otherwise, it is appended to the
* end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
JsonCache add(JsonPointer ptr, BigDecimal value) throws CacheException;
/**
* Adds a <code>BigInteger</code> to an array. The array is created if it does not already exist.
*
* @param ptr A pointer to the property to set. If the last segment is a positive integer less than the current
* array size, <code>value</code> is inserted at the specified index; otherwise, it is appended to the
* end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
JsonCache add(JsonPointer ptr, BigInteger value) throws CacheException;
/**
* Adds a <code>boolean</code> to an array. The array is created if it does not already exist.
*
* @param ptr A pointer to the property to set. If the last segment is a positive integer less than the current
* array size, <code>value</code> is inserted at the specified index; otherwise, it is appended to the
* end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
JsonCache add(JsonPointer ptr, boolean value) throws CacheException;
/**
* Adds a <code>double</code> value to an array. The array is created if it does not already exist.
*
* @param ptr A pointer to the property to set. If the last segment is a positive integer less than the current
* array size, <code>value</code> is inserted at the specified index; otherwise, it is appended to the
* end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
JsonCache add(JsonPointer ptr, double value) throws CacheException;
/**
* Adds a <code>float</code> value to an array. The array is created if it does not already exist.
*
* @param ptr A pointer to the property to set. If the last segment is a positive integer less than the current
* array size, <code>value</code> is inserted at the specified index; otherwise, it is appended to the
* end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
JsonCache add(JsonPointer ptr, float value) throws CacheException;
/**
* Adds an <code>int</code> value to an array. The array is created if it does not already exist.
*
* @param ptr A pointer to the property to set. If the last segment is a positive integer less than the current
* array size, <code>value</code> is inserted at the specified index; otherwise, it is appended to the
* end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
JsonCache add(JsonPointer ptr, int value) throws CacheException;
/**
* Adds a <code>long</code> value to an array. The array is created if it does not already exist.
*
* @param ptr A pointer to the property to set. If the last segment is a positive integer less than the current
* array size, <code>value</code> is inserted at the specified index; otherwise, it is appended to the
* end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
JsonCache add(JsonPointer ptr, long value) throws CacheException;
/**
* Adds an object to an array. The array is created if it does not already exist.
*
* @param ptr A pointer to the property to set. If the last segment is a positive integer less than the current
* array size, <code>value</code> is inserted at the specified index; otherwise, it is appended to the
* end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
JsonCache add(JsonPointer ptr, Object value) throws CacheException;
/**
* Adds a <code>short</code> value to an array. The array is created if it does not already exist.
*
* @param ptr A pointer to the property to set. If the last segment is a positive integer less than the current
* array size, <code>value</code> is inserted at the specified index; otherwise, it is appended to the
* end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
JsonCache add(JsonPointer ptr, short value) throws CacheException;
/**
* Adds a <code>BigDecimal</code> to an array. The array is created if it does not already exist.
*
* @param path A JSON Pointer expression for the property to set. If the last segment is a positive integer less
* than the current array size, <code>value</code> is inserted at the specified index; otherwise, it is
* appended to the end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
*/
JsonCache add(String path, BigDecimal value) throws CacheException;
/**
* Adds a <code>BigInteger</code> to an array. The array is created if it does not already exist.
*
* @param path A JSON Pointer expression for the property to set. If the last segment is a positive integer less
* than the current array size, <code>value</code> is inserted at the specified index; otherwise, it is
* appended to the end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
*/
JsonCache add(String path, BigInteger value) throws CacheException;
/**
* Adds a <code>boolean</code> value to an array. The array is created if it does not already exist.
*
* @param path A JSON Pointer expression for the property to set. If the last segment is a positive integer less
* than the current array size, <code>value</code> is inserted at the specified index; otherwise, it is
* appended to the end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
*/
JsonCache add(String path, boolean value) throws CacheException;
/**
* Adds a <code>double</code> value to an array. The array is created if it does not already exist.
*
* @param path A JSON Pointer expression for the property to set. If the last segment is a positive integer less
* than the current array size, <code>value</code> is inserted at the specified index; otherwise, it is
* appended to the end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
*/
JsonCache add(String path, double value) throws CacheException;
/**
* Adds a <code>float</code> value to an array. The array is created if it does not already exist.
*
* @param path A JSON Pointer expression for the property to set. If the last segment is a positive integer less
* than the current array size, <code>value</code> is inserted at the specified index; otherwise, it is
* appended to the end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
*/
JsonCache add(String path, float value) throws CacheException;
/**
* Adds an <code>int</code> value to an array. The array is created if it does not already exist.
*
* @param path A JSON Pointer expression for the property to set. If the last segment is a positive integer less
* than the current array size, <code>value</code> is inserted at the specified index; otherwise, it is
* appended to the end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
*/
JsonCache add(String path, int value) throws CacheException;
/**
* Adds a <code>long</code> value to an array. The array is created if it does not already exist.
*
* @param path A JSON Pointer expression for the property to set. If the last segment is a positive integer less
* than the current array size, <code>value</code> is inserted at the specified index; otherwise, it is
* appended to the end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
*/
JsonCache add(String path, long value) throws CacheException;
/**
* Adds an object to an array. The array is created if it does not already exist.
*
* @param path A JSON Pointer expression for the property to set. If the last segment is a positive integer less
* than the current array size, <code>value</code> is inserted at the specified index; otherwise, it is
* appended to the end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
*/
JsonCache add(String path, Object value) throws CacheException;
/**
* Adds a <code>short</code> value to an array. The array is created if it does not already exist.
*
* @param path A JSON Pointer expression for the property to set. If the last segment is a positive integer less
* than the current array size, <code>value</code> is inserted at the specified index; otherwise, it is
* appended to the end of the array.
* @param value The value to add.
* @return The receiver, to support chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
*/
JsonCache add(String path, short value) throws CacheException;
/**
* Returns a child cache rooted at the given location relative to the receiver's base pointer.
*
* @param ptr A pointer to the subtree managed by the new cache.
* @return The child cache.
* @throws NullPointerException if <code>ptr</code> is <code>null</code>.
*/
JsonCache child(JsonPointer ptr);
/**
* Returns a child cache rooted at the given location relative to the receiver's base pointer.
*
* @param path A JSON Pointer expression for the subtree managed by the new cache. Note that the expression must
* start with a forward slash character.
* @return The child cache.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
JsonCache child(String path);
/**
* Deletes a property within the object graph managed by the receiver.
*
* @param ptr A pointer to the property to set.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
void delete(JsonPointer ptr) throws CacheException;
/**
* Deletes a property within the object graph managed by the receiver.
*
* @param path A JSON Pointer expression for the property to set.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the
* receiver.
*/
void delete(String path) throws CacheException;
/**
* Tests for the existence of the specified path within the object graph managed by the receiver.
*
* @param ptr A pointer to the path to test.
* @return <code>true</code> if a JSON node corresponding to <code>ptr</code> exists.
*/
boolean exists(JsonPointer ptr);
/**
* Tests for the existence of the specified path within the object graph managed by the receiver.
*
* @param path A JSON Pointer expression for the path to test.
* @return <code>true</code> if a JSON node corresponding to <code>ptr</code> exists.
*/
boolean exists(String path);
/**
* Retrieves an <code>Object</code> value from within the graph.
*
* @param ptr A JSON Pointer expression for the value to return.
* @return the property value or <code>null</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
Object get(JsonPointer ptr) throws CacheException;
/**
* Retrieves an <code>Object</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param ptr A pointer to the value to return.
* @param defaultValue The default value to return if <code>ptr</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
Object get(JsonPointer ptr, Object defaultValue) throws CacheException;
/**
* Retrieves an <code>Object</code> value from within the graph.
*
* @param path A pointer to the value to return.
* @return the property value or <code>null</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
Object get(String path) throws CacheException;
/**
* Retrieves an <code>Object</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param path A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>path</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
Object get(String path, Object defaultValue) throws CacheException;
/**
* Retrieves a <code>BigDecimal</code> value from within the graph.
*
* @param ptr A pointer to the value to retrieve.
* @return the property value or <code>null</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
BigDecimal getBigDecimal(JsonPointer ptr) throws CacheException;
/**
* Retrieves a <code>BigDecimal</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param ptr A pointer to the value to return.
* @param defaultValue The default value to return if <code>ptr</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
BigDecimal getBigDecimal(JsonPointer ptr, BigDecimal defaultValue) throws CacheException;
/**
* Retrieves a <code>BigDecimal</code> value from within the graph.
*
* @param path A JSON Pointer expression for the value to retrieve.
* @return the property value or <code>null</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
BigDecimal getBigDecimal(String path) throws CacheException;
/**
* Retrieves a <code>BigDecimal</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param path A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>path</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
BigDecimal getBigDecimal(String path, BigDecimal defaultValue) throws CacheException;
/**
* Retrieves a <code>BigInteger</code> value from within the graph.
*
* @param ptr A pointer to the value to retrieve.
* @return the property value or <code>null</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
BigInteger getBigInteger(JsonPointer ptr) throws CacheException;
/**
* Retrieves a <code>BigInteger</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param ptr A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>ptr</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
BigInteger getBigInteger(JsonPointer ptr, BigInteger defaultValue) throws CacheException;
/**
* Retrieves a <code>BigInteger</code> value from within the graph.
*
* @param path A JSON Pointer expression for the value to retrieve.
* @return the property value or <code>null</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
BigInteger getBigInteger(String path) throws CacheException;
/**
* Retrieves a <code>BigInteger</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param path A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>path</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
BigInteger getBigInteger(String path, BigInteger defaultValue) throws CacheException;
/**
* Retrieves a <code>byte[]</code> value from within the graph.
*
* @param ptr A pointer to the value to retrieve.
* @return the property value or <code>null</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
byte[] getBinary(JsonPointer ptr) throws CacheException;
/**
* Retrieves a <code>byte[]</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param ptr A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>ptr</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
byte[] getBinary(JsonPointer ptr, byte[] defaultValue) throws CacheException;
/**
* Retrieves a <code>byte[]</code> value from within the graph.
*
* @param path A JSON Pointer expression for the value to retrieve.
* @return the property value or <code>null</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
byte[] getBinary(String path) throws CacheException;
/**
* Retrieves a <code>byte[]</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param path A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>path</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
byte[] getBinary(String path, byte[] defaultValue) throws CacheException;
/**
* Retrieves a <code>boolean</code> value from within the graph.
*
* @param ptr A pointer to the value to retrieve.
* @return the property value or <code>false</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
boolean getBoolean(JsonPointer ptr) throws CacheException;
/**
* Retrieves a <code>boolean</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param ptr A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>ptr</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
boolean getBoolean(JsonPointer ptr, boolean defaultValue) throws CacheException;
/**
* Retrieves a <code>boolean</code> value from within the graph.
*
* @param path A JSON Pointer expression for the value to retrieve.
* @return the property value or <code>false</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
boolean getBoolean(String path) throws CacheException;
/**
* Retrieves a <code>boolean</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param path A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>path</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
boolean getBoolean(String path, boolean defaultValue) throws CacheException;
/**
* Retrieves a <code>double</code> value from within the graph.
*
* @param ptr A pointer to the value to retrieve.
* @return the property value or <code>0.0D</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
double getDouble(JsonPointer ptr) throws CacheException;
/**
* Retrieves a <code>double</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param ptr A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>ptr</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
double getDouble(JsonPointer ptr, double defaultValue) throws CacheException;
/**
* Retrieves a <code>double</code> value from within the graph.
*
* @param path A JSON Pointer expression for the value to retrieve.
* @return the property value or <code>0.0D</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
double getDouble(String path) throws CacheException;
/**
* Retrieves a <code>double</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param path A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>path</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
double getDouble(String path, double defaultValue) throws CacheException;
/**
* Retrieves a <code>float</code> value from within the graph.
*
* @param ptr A pointer to the value to retrieve.
* @return the property value or <code>0.0F</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
float getFloat(JsonPointer ptr) throws CacheException;
/**
* Retrieves a <code>float</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param ptr A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>ptr</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
float getFloat(JsonPointer ptr, float defaultValue) throws CacheException;
/**
* Retrieves a <code>float</code> value from within the graph.
*
* @param path A JSON Pointer expression for the value to retrieve.
* @return the property value or <code>0.0F</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
float getFloat(String path) throws CacheException;
/**
* Retrieves a <code>float</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param path A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>path</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
float getFloat(String path, float defaultValue) throws CacheException;
/**
* Retrieves an <code>int</code> value from within the graph.
*
* @param ptr A pointer to the value to retrieve.
* @return the property value or <code>0</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
int getInt(JsonPointer ptr) throws CacheException;
/**
* Retrieves an <code>int</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param ptr A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>ptr</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
int getInt(JsonPointer ptr, int defaultValue) throws CacheException;
/**
* Retrieves an <code>int</code> value from within the graph.
*
* @param path A JSON Pointer expression for the value to retrieve.
* @return the property value or <code>0</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
int getInt(String path) throws CacheException;
/**
* Retrieves an <code>int</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param path A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>path</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
int getInt(String path, int defaultValue) throws CacheException;
/**
* Retrieves a <code>long</code> value from within the graph.
*
* @param ptr A pointer to the value to retrieve.
* @return the property value or <code>0L</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
long getLong(JsonPointer ptr) throws CacheException;
/**
* Retrieves a <code>long</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param ptr A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>ptr</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
long getLong(JsonPointer ptr, long defaultValue) throws CacheException;
/**
* Retrieves a <code>long</code> value from within the graph.
*
* @param path A JSON Pointer expression for the value to retrieve.
* @return the property value or <code>0L</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
long getLong(String path) throws CacheException;
/**
* Retrieves a <code>long</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param path A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>path</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
long getLong(String path, long defaultValue) throws CacheException;
/**
* Returns the node type at the specified location in the object graph.
*
* @param ptr A pointer to the node to test.
* @return The node type.
*/
JsonNodeType getNodeType(JsonPointer ptr);
/**
* Returns the node type at the specified location in the object graph.
*
* @param path A JSON Pointer expression for the node to test.
* @return The node type.
*/
JsonNodeType getNodeType(String path);
/**
* Retrieves a <code>Number</code> value from within the graph.
*
* @param ptr A pointer to the value to retrieve.
* @return the property value or <code>null</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
Number getNumber(JsonPointer ptr) throws CacheException;
/**
* Retrieves a <code>Number</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param ptr A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>ptr</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
Number getNumber(JsonPointer ptr, Number defaultValue) throws CacheException;
/**
* Retrieves a <code>Number</code> value from within the graph.
*
* @param path A JSON Pointer expression for the value to retrieve.
* @return the property value or <code>null</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
Number getNumber(String path) throws CacheException;
/**
* Retrieves a <code>Number</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param path A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>path</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
Number getNumber(String path, Number defaultValue) throws CacheException;
/**
* Retrieves a typed object value from within the graph.
*
* @param <T> The type of object to return.
* @param ptr A pointer to the value to return.
* @param type The type of object to return.
* @return the property value or <code>null</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver or
* if the node could not be converted to the requested type.
*/
<T> T getObject(JsonPointer ptr, Class<T> type) throws CacheException;
/**
* Retrieves a typed object value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param <T> The type of the object to return.
* @param ptr A pointer to the value to return.
* @param defaultValue The default value to return if <code>ptr</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver or
* if the node could not be converted to the requested type.
*/
<T> T getObject(JsonPointer ptr, T defaultValue) throws CacheException;
/**
* Retrieves a typed object value from within the graph.
*
* @param <T> The type of object to return.
* @param path A JSON pointer expression for the value to return.
* @param type The type of object to return.
* @return the property value or <code>null</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver or if the node could not be converted to the requested type.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
<T> T getObject(String path, Class<T> type) throws CacheException;
/**
* Retrieves a typed object value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param <T> The type of the object to return.
* @param path A JSON pointer expression for the value to return.
* @param defaultValue The default value to return if <code>path</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver or if the node could not be converted to the requested type.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
<T> T getObject(String path, T defaultValue) throws CacheException;
/**
* Retrieves a typed list of objects from within the graph.
*
* @param <T> The list element type.
* @param ptr A pointer to the values to return.
* @param type The list element type.
* @return the property values.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver or
* if the nodes could not be converted to the requested type.
*/
<T> List<T> getObjects(JsonPointer ptr, Class<T> type) throws CacheException;
/**
* Retrieves a typed list of objects from within the graph. If the values are not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param <T> The list element type.
* @param ptr A pointer to the values to return.
* @param type The list element type.
* @param defaultValue The default values to return if <code>ptr</code> is not present in the graph.
* @return the property values.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver or
* if the nodes could not be converted to the requested type.
*/
<T> List<T> getObjects(JsonPointer ptr, Class<T> type, List<T> defaultValue) throws CacheException;
/**
* Retrieves a typed list of objects from within the graph.
*
* @param <T> The list element type.
* @param path A JSON Pointer expression for the values to return.
* @param type The list element type.
* @return the property values.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver or if the nodes could not be converted to the requested type.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
<T> List<T> getObjects(String path, Class<T> type) throws CacheException;
/**
* Retrieves a typed list of objects from within the graph. If the values are not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param <T> The list element type.
* @param path A JSON Pointer expression for the values to return.
* @param type The list element type.
* @param defaultValue The default values to return if <code>path</code> is not present in the graph.
* @return the property values.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the
* receiver or if the nodes could not be converted to the requested type.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
<T> List<T> getObjects(String path, Class<T> type, List<T> defaultValue) throws CacheException;
/**
* Retrieves a <code>short</code> value from within the graph.
*
* @param ptr A pointer to the value to retrieve.
* @return the property value or <code>0</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
short getShort(JsonPointer ptr) throws CacheException;
/**
* Retrieves a <code>short</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param ptr A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>ptr</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
short getShort(JsonPointer ptr, short defaultValue) throws CacheException;
/**
* Retrieves a <code>short</code> value from within the graph.
*
* @param path A JSON Pointer expression for the value to retrieve.
* @return the property value or <code>0</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
short getShort(String path) throws CacheException;
/**
* Retrieves a <code>short</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param path A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>path</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
short getShort(String path, short defaultValue) throws CacheException;
/**
* Retrieves a <code>String</code> value from within the graph.
*
* @param ptr A pointer to the value to retrieve.
* @return the property value or <code>null</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
String getString(JsonPointer ptr) throws CacheException;
/**
* Retrieves a <code>String</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param ptr A pointer to the value to return.
* @param defaultValue The default value to return if <code>ptr</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
*/
String getString(JsonPointer ptr, String defaultValue) throws CacheException;
/**
* Retrieves a <code>String</code> value from within the graph.
*
* @param path A JSON Pointer expression for the value to retrieve.
* @return the property value or <code>null</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
String getString(String path) throws CacheException;
/**
* Retrieves a <code>String</code> value from within the graph. If the value is not present, stores
* <code>defaultValue</code> at the specified location and returns this value.
*
* @param path A JSON Pointer expression for the value to return.
* @param defaultValue The default value to return if <code>path</code> is not present in the graph.
* @return the property value or <code>defaultValue</code> if not present.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON path expression.
*/
String getString(String path, String defaultValue) throws CacheException;
/**
* Returns the parent cache of which this is a descendant.
*
* @return The parent cache, <code>null</code> if the receiver is the root cache.
*/
JsonCache parent();
/**
* Returns the root cache of which this is a descendant.
*
* @return The root cache. The root cache returns itself.
*/
Root root();
/**
* Sets a <code>BigDecimal</code> property within the object graph managed by the receiver.
*
* @param ptr A pointer to the property to set.
* @param value The value to set (can be null).
* @return The receiver, to allow chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
* @see #delete(JsonPointer)
*/
JsonCache set(JsonPointer ptr, BigDecimal value) throws CacheException;
/**
* Sets a <code>BigInteger</code> property within the object graph managed by the receiver.
*
* @param ptr A pointer to the property to set.
* @param value The value to set (can be null).
* @return The receiver, to allow chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
* @see #delete(JsonPointer)
*/
JsonCache set(JsonPointer ptr, BigInteger value) throws CacheException;
/**
* Sets a <code>boolean</code> property within the object graph managed by the receiver.
*
* @param ptr A pointer to the property to set.
* @param value The value to set.
* @return The receiver, to allow chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
* @see #delete(JsonPointer)
*/
JsonCache set(JsonPointer ptr, boolean value) throws CacheException;
/**
* Sets a <code>double</code> property within the object graph managed by the receiver.
*
* @param ptr A pointer to the property to set.
* @param value The value to set.
* @return The receiver, to allow chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
* @see #delete(JsonPointer)
*/
JsonCache set(JsonPointer ptr, double value) throws CacheException;
/**
* Sets a <code>float</code> property within the object graph managed by the receiver.
*
* @param ptr A pointer to the property to set.
* @param value The value to set.
* @return The receiver, to allow chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
* @see #delete(JsonPointer)
*/
JsonCache set(JsonPointer ptr, float value) throws CacheException;
/**
* Sets an <code>int</code> property within the object graph managed by the receiver.
*
* @param ptr A pointer to the property to set.
* @param value The value to set.
* @return The receiver, to allow chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
* @see #delete(JsonPointer)
*/
JsonCache set(JsonPointer ptr, int value) throws CacheException;
/**
* Sets a <code>List</code> property within the object graph managed by the receiver.
*
* @param ptr A pointer to the property to set.
* @param values The values to set.
* @return The receiver, to allow chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
* @see #delete(JsonPointer)
*/
JsonCache set(JsonPointer ptr, List<?> values) throws CacheException;
/**
* Sets a <code>long</code> property within the object graph managed by the receiver.
*
* @param ptr A pointer to the property to set.
* @param value The value to set.
* @return The receiver, to allow chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
* @see #delete(JsonPointer)
*/
JsonCache set(JsonPointer ptr, long value) throws CacheException;
/**
* Sets an <code>Object</code> property within the object graph managed by the receiver.
*
* @param ptr A pointer to the property to set.
* @param value The value to set (can be null).
* @return The receiver, to allow chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
* @see #delete(JsonPointer)
*/
JsonCache set(JsonPointer ptr, Object value) throws CacheException;
/**
* Sets a <code>short</code> property within the object graph managed by the receiver.
*
* @param ptr A pointer to the property to set.
* @param value The value to set.
* @return The receiver, to allow chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
* @see #delete(JsonPointer)
*/
JsonCache set(JsonPointer ptr, short value) throws CacheException;
/**
* Sets a <code>String</code> property within the object graph managed by the receiver.
*
* @param ptr A pointer to the property to set.
* @param value The value to set (can be null).
* @return The receiver, to allow chaining.
* @throws CacheException if <code>ptr</code> is not a valid path within the object graph managed by the receiver.
* @see #delete(JsonPointer)
*/
JsonCache set(JsonPointer ptr, String value) throws CacheException;
/**
* Sets a <code>BigDecimal</code> property within the object graph managed by the receiver.
*
* @param path A JSON Pointer expression for the property to set.
* @param value The value to set (can be null).
* @return The receiver, to allow chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON Pointer expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @see #delete(String)
*/
JsonCache set(String path, BigDecimal value) throws CacheException;
/**
* Sets a <code>BigInteger</code> property within the object graph managed by the receiver.
*
* @param path A JSON Pointer expression for the property to set.
* @param value The value to set (can be null).
* @return The receiver, to allow chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON Pointer expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @see #delete(String)
*/
JsonCache set(String path, BigInteger value) throws CacheException;
/**
* Sets a <code>boolean</code> property within the object graph managed by the receiver.
*
* @param path A JSON Pointer expression for the property to set.
* @param value The value to set.
* @return The receiver, to allow chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON Pointer expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @see #delete(String)
*/
JsonCache set(String path, boolean value) throws CacheException;
/**
* Sets a <code>double</code> property within the object graph managed by the receiver.
*
* @param path A JSON Pointer expression for the property to set.
* @param value The value to set.
* @return The receiver, to allow chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON Pointer expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @see #delete(String)
*/
JsonCache set(String path, double value) throws CacheException;
/**
* Sets a <code>float</code> property within the object graph managed by the receiver.
*
* @param path A JSON Pointer expression for the property to set.
* @param value The value to set.
* @return The receiver, to allow chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON Pointer expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @see #delete(String)
*/
JsonCache set(String path, float value) throws CacheException;
/**
* Sets an <code>int</code> property within the object graph managed by the receiver.
*
* @param path A JSON Pointer expression for the property to set.
* @param value The value to set.
* @return The receiver, to allow chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON Pointer expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @see #delete(String)
*/
JsonCache set(String path, int value) throws CacheException;
/**
* Sets a <code>List</code> property within the object graph managed by the receiver.
*
* @param path A JSON Pointer expression for the property to set.
* @param values The values to set.
* @return The receiver, to allow chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON Pointer expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @see #delete(String)
*/
JsonCache set(String path, List<?> values) throws CacheException;
/**
* Sets a <code>long</code> property within the object graph managed by the receiver.
*
* @param path A JSON Pointer expression for the property to set.
* @param value The value to set.
* @return The receiver, to allow chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON Pointer expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @see #delete(String)
*/
JsonCache set(String path, long value) throws CacheException;
/**
* Sets an <code>Object</code> property within the object graph managed by the receiver.
*
* @param path A JSON Pointer expression for the property to set.
* @param value The value to set (can be null).
* @return The receiver, to allow chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON Pointer expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @see #delete(String)
*/
JsonCache set(String path, Object value) throws CacheException;
/**
* Sets a <code>short</code> property within the object graph managed by the receiver.
*
* @param path A JSON Pointer expression for the property to set.
* @param value The value to set.
* @return The receiver, to allow chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON Pointer expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @see #delete(String)
*/
JsonCache set(String path, short value) throws CacheException;
/**
* Sets a <code>String</code> property within the object graph managed by the receiver.
*
* @param path A JSON Pointer expression for the property to set.
* @param value The value to set (can be null).
* @return The receiver, to allow chaining.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON Pointer expression.
* @throws CacheException if <code>path</code> is not a valid path within the object graph managed by the
* receiver.
* @see #delete(String)
*/
JsonCache set(String path, String value) throws CacheException;
/**
* Returns the size of a node within the object graph managed by the receiver. For an array node, size is the number
* of elements; for an object node, size is the number of properties; for other node types, size is <code>0</code>.
*
* @param ptr A pointer to the node.
* @return The size of the node, or <code>0</code> if it does not exist.
* @see #delete(String)
*/
int size(JsonPointer ptr);
/**
* Returns the size of a node within the object graph managed by the receiver. For an array node, size is the number
* of elements; for an object node, size is the number of properties; for other node types, size is <code>0</code>.
*
* @param path A JSON pointer expression for the node.
* @return The size of the node, or <code>0</code> if it does not exist.
* @throws IllegalArgumentException if <code>path</code> is not a valid JSON Pointer expression.
* @see #delete(String)
*/
int size(String path);
}
\ No newline at end of file
/*
* 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 com.ibizlab.codegen.utils;
import com.fasterxml.jackson.core.JsonPointer;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Pattern;
/**
* A cache implementation for loading, querying, mutating and saving a JSON object graph.
*
* @author Adrian Price, TIBCO Software Inc.
* @since 4.0.0
*/
class JsonCacheImpl implements JsonCache.Root {
/**
* Manages a sub-tree of a parent cache, identified by a base pointer rooted.
*/
private static class ChildCacheImpl implements JsonCache {
private final JsonPointer basePtr;
private final JsonCache parent;
private ChildCacheImpl(JsonCache parent, JsonPointer basePtr) {
this.parent = parent;
this.basePtr = basePtr;
}
@Override
public JsonCache add(JsonPointer ptr, BigDecimal value) throws CacheException {
parent.add(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache add(JsonPointer ptr, BigInteger value) throws CacheException {
parent.add(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache add(JsonPointer ptr, boolean value) throws CacheException {
parent.add(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache add(JsonPointer ptr, double value) throws CacheException {
parent.add(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache add(JsonPointer ptr, float value) throws CacheException {
parent.add(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache add(JsonPointer ptr, int value) throws CacheException {
parent.add(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache add(JsonPointer ptr, long value) throws CacheException {
parent.add(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache add(JsonPointer ptr, Object value) throws CacheException {
parent.add(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache add(JsonPointer ptr, short value) throws CacheException {
parent.add(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache add(String path, BigDecimal value) throws CacheException {
parent.add(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache add(String path, BigInteger value) throws CacheException {
parent.add(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache add(String path, boolean value) throws CacheException {
parent.add(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache add(String path, double value) throws CacheException {
parent.add(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache add(String path, float value) throws CacheException {
parent.add(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache add(String path, int value) throws CacheException {
parent.add(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache add(String path, long value) throws CacheException {
parent.add(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache add(String path, Object value) throws CacheException {
parent.add(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache add(String path, short value) throws CacheException {
parent.add(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache child(JsonPointer basePtr) {
return new ChildCacheImpl(this, basePtr);
}
@Override
public JsonCache child(String path) {
return child(JsonPointer.compile(path));
}
@Override
public void delete(JsonPointer ptr) throws CacheException {
parent.delete(basePtr.append(ptr));
}
@Override
public void delete(String path) throws CacheException {
parent.delete(basePtr.append(JsonPointer.compile(path)));
}
@Override
public boolean exists(JsonPointer ptr) {
return parent.exists(basePtr.append(ptr));
}
@Override
public boolean exists(String path) {
return parent.exists(basePtr.append(JsonPointer.compile(path)));
}
@Override
public Object get(JsonPointer ptr) throws CacheException {
return parent.get(basePtr.append(ptr));
}
@Override
public Object get(JsonPointer ptr, Object defaultValue) throws CacheException {
return parent.get(basePtr.append(ptr), defaultValue);
}
@Override
public Object get(String path) throws CacheException {
return parent.get(basePtr.append(JsonPointer.compile(path)));
}
@Override
public Object get(String path, Object defaultValue) throws CacheException {
return parent.get(basePtr.append(JsonPointer.compile(path)), defaultValue);
}
@Override
public BigDecimal getBigDecimal(JsonPointer ptr) throws CacheException {
return parent.getBigDecimal(basePtr.append(ptr));
}
@Override
public BigDecimal getBigDecimal(JsonPointer ptr, BigDecimal defaultValue) throws CacheException {
return parent.getBigDecimal(basePtr.append(ptr), defaultValue);
}
@Override
public BigDecimal getBigDecimal(String path) throws CacheException {
return parent.getBigDecimal(basePtr.append(JsonPointer.compile(path)));
}
@Override
public BigDecimal getBigDecimal(String path, BigDecimal defaultValue) throws CacheException {
return parent.getBigDecimal(basePtr.append(JsonPointer.compile(path)), defaultValue);
}
@Override
public BigInteger getBigInteger(JsonPointer ptr) throws CacheException {
return parent.getBigInteger(basePtr.append(ptr));
}
@Override
public BigInteger getBigInteger(JsonPointer ptr, BigInteger defaultValue) throws CacheException {
return parent.getBigInteger(basePtr.append(ptr), defaultValue);
}
@Override
public BigInteger getBigInteger(String path) throws CacheException {
return parent.getBigInteger(basePtr.append(JsonPointer.compile(path)));
}
@Override
public BigInteger getBigInteger(String path, BigInteger defaultValue) throws CacheException {
return parent.getBigInteger(basePtr.append(JsonPointer.compile(path)), defaultValue);
}
@Override
public byte[] getBinary(JsonPointer ptr) throws CacheException {
return parent.getBinary(basePtr.append(ptr));
}
@Override
public byte[] getBinary(JsonPointer ptr, byte[] defaultValue) throws CacheException {
return parent.getBinary(basePtr.append(ptr), defaultValue);
}
@Override
public byte[] getBinary(String path) throws CacheException {
return parent.getBinary(basePtr.append(JsonPointer.compile(path)));
}
@Override
public byte[] getBinary(String path, byte[] defaultValue) throws CacheException {
return parent.getBinary(basePtr.append(JsonPointer.compile(path)), defaultValue);
}
@Override
public boolean getBoolean(JsonPointer ptr) throws CacheException {
return parent.getBoolean(basePtr.append(ptr));
}
@Override
public boolean getBoolean(JsonPointer ptr, boolean defaultValue) throws CacheException {
return parent.getBoolean(basePtr.append(ptr), defaultValue);
}
@Override
public boolean getBoolean(String path) throws CacheException {
return parent.getBoolean(basePtr.append(JsonPointer.compile(path)));
}
@Override
public boolean getBoolean(String path, boolean defaultValue) throws CacheException {
return parent.getBoolean(basePtr.append(JsonPointer.compile(path)), defaultValue);
}
@Override
public double getDouble(JsonPointer ptr) throws CacheException {
return parent.getDouble(basePtr.append(ptr));
}
@Override
public double getDouble(JsonPointer ptr, double defaultValue) throws CacheException {
return parent.getDouble(basePtr.append(ptr), defaultValue);
}
@Override
public double getDouble(String path) throws CacheException {
return parent.getDouble(basePtr.append(JsonPointer.compile(path)));
}
@Override
public double getDouble(String path, double defaultValue) throws CacheException {
return parent.getDouble(basePtr.append(JsonPointer.compile(path)), defaultValue);
}
@Override
public float getFloat(JsonPointer ptr) throws CacheException {
return parent.getFloat(basePtr.append(ptr));
}
@Override
public float getFloat(JsonPointer ptr, float defaultValue) throws CacheException {
return parent.getFloat(basePtr.append(ptr), defaultValue);
}
@Override
public float getFloat(String path) throws CacheException {
return parent.getFloat(basePtr.append(JsonPointer.compile(path)));
}
@Override
public float getFloat(String path, float defaultValue) throws CacheException {
return parent.getFloat(basePtr.append(JsonPointer.compile(path)), defaultValue);
}
@Override
public int getInt(JsonPointer ptr) throws CacheException {
return parent.getInt(basePtr.append(ptr));
}
@Override
public int getInt(JsonPointer ptr, int defaultValue) throws CacheException {
return parent.getInt(basePtr.append(ptr), defaultValue);
}
@Override
public int getInt(String path) throws CacheException {
return parent.getInt(basePtr.append(JsonPointer.compile(path)));
}
@Override
public int getInt(String path, int defaultValue) throws CacheException {
return parent.getInt(basePtr.append(JsonPointer.compile(path)), defaultValue);
}
@Override
public long getLong(JsonPointer ptr) throws CacheException {
return parent.getLong(basePtr.append(ptr));
}
@Override
public long getLong(JsonPointer ptr, long defaultValue) throws CacheException {
return parent.getLong(basePtr.append(ptr), defaultValue);
}
@Override
public long getLong(String path) throws CacheException {
return parent.getLong(basePtr.append(JsonPointer.compile(path)));
}
@Override
public long getLong(String path, long defaultValue) throws CacheException {
return parent.getLong(basePtr.append(JsonPointer.compile(path)), defaultValue);
}
@Override
public JsonNodeType getNodeType(JsonPointer ptr) {
return parent.getNodeType(basePtr.append(ptr));
}
@Override
public JsonNodeType getNodeType(String path) {
return parent.getNodeType(basePtr.append(JsonPointer.compile(path)));
}
@Override
public Number getNumber(JsonPointer ptr) throws CacheException {
return parent.getNumber(basePtr.append(ptr));
}
@Override
public Number getNumber(JsonPointer ptr, Number defaultValue) throws CacheException {
return parent.getNumber(basePtr.append(ptr), defaultValue);
}
@Override
public Number getNumber(String path) throws CacheException {
return parent.getNumber(basePtr.append(JsonPointer.compile(path)));
}
@Override
public Number getNumber(String path, Number defaultValue) throws CacheException {
return parent.getNumber(basePtr.append(JsonPointer.compile(path)), defaultValue);
}
@Override
public <T> T getObject(JsonPointer ptr, Class<T> type) throws CacheException {
return parent.getObject(basePtr.append(ptr), type);
}
@Override
public <T> T getObject(JsonPointer ptr, T defaultValue) throws CacheException {
return parent.getObject(basePtr.append(ptr), defaultValue);
}
@Override
public <T> T getObject(String path, Class<T> type) throws CacheException {
return parent.getObject(basePtr.append(JsonPointer.compile(path)), type);
}
@Override
public <T> T getObject(String path, T defaultValue) throws CacheException {
return parent.getObject(basePtr.append(JsonPointer.compile(path)), defaultValue);
}
@Override
public <T> List<T> getObjects(JsonPointer ptr, Class<T> type) throws CacheException {
return parent.getObjects(basePtr.append(ptr), type);
}
@Override
public <T> List<T> getObjects(JsonPointer ptr, Class<T> type, List<T> defaultValue) throws CacheException {
return parent.getObjects(basePtr.append(ptr), type, defaultValue);
}
@Override
public <T> List<T> getObjects(String path, Class<T> type) throws CacheException {
return parent.getObjects(basePtr.append(JsonPointer.compile(path)), type);
}
@Override
public <T> List<T> getObjects(String path, Class<T> type, List<T> defaultValue) throws CacheException {
return parent.getObjects(basePtr.append(JsonPointer.compile(path)), type, defaultValue);
}
@Override
public short getShort(JsonPointer ptr) throws CacheException {
return parent.getShort(basePtr.append(ptr));
}
@Override
public short getShort(JsonPointer ptr, short defaultValue) throws CacheException {
return parent.getShort(basePtr.append(ptr), defaultValue);
}
@Override
public short getShort(String path) throws CacheException {
return parent.getShort(basePtr.append(JsonPointer.compile(path)));
}
@Override
public short getShort(String path, short defaultValue) throws CacheException {
return parent.getShort(basePtr.append(JsonPointer.compile(path)), defaultValue);
}
@Override
public String getString(JsonPointer ptr) throws CacheException {
return parent.getString(basePtr.append(ptr));
}
@Override
public String getString(JsonPointer ptr, String defaultValue) throws CacheException {
return parent.getString(basePtr.append(ptr), defaultValue);
}
@Override
public String getString(String path) throws CacheException {
return parent.getString(basePtr.append(JsonPointer.compile(path)));
}
@Override
public String getString(String path, String defaultValue) throws CacheException {
return parent.getString(basePtr.append(JsonPointer.compile(path)), defaultValue);
}
@Override
public JsonCache parent() {
return parent;
}
@Override
public Root root() {
return parent.root();
}
@Override
public JsonCache set(JsonPointer ptr, BigDecimal value) throws CacheException {
parent.set(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache set(JsonPointer ptr, BigInteger value) throws CacheException {
parent.set(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache set(JsonPointer ptr, boolean value) throws CacheException {
parent.set(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache set(JsonPointer ptr, double value) throws CacheException {
parent.set(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache set(JsonPointer ptr, float value) throws CacheException {
parent.set(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache set(JsonPointer ptr, int value) throws CacheException {
parent.set(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache set(JsonPointer ptr, List<?> values) throws CacheException {
parent.set(basePtr.append(ptr), values);
return this;
}
@Override
public JsonCache set(JsonPointer ptr, long value) throws CacheException {
parent.set(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache set(JsonPointer ptr, Object value) throws CacheException {
parent.set(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache set(JsonPointer ptr, short value) throws CacheException {
parent.set(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache set(JsonPointer ptr, String value) throws CacheException {
parent.set(basePtr.append(ptr), value);
return this;
}
@Override
public JsonCache set(String path, BigDecimal value) throws CacheException {
parent.set(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache set(String path, BigInteger value) throws CacheException {
parent.set(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache set(String path, boolean value) throws CacheException {
parent.set(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache set(String path, double value) throws CacheException {
parent.set(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache set(String path, float value) throws CacheException {
parent.set(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache set(String path, int value) throws CacheException {
parent.set(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache set(String path, List<?> values) throws CacheException {
parent.set(basePtr.append(JsonPointer.compile(path)), values);
return this;
}
@Override
public JsonCache set(String path, long value) throws CacheException {
parent.set(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache set(String path, Object value) throws CacheException {
parent.set(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache set(String path, short value) throws CacheException {
parent.set(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public JsonCache set(String path, String value) throws CacheException {
parent.set(basePtr.append(JsonPointer.compile(path)), value);
return this;
}
@Override
public int size(JsonPointer ptr) {
return parent.size(basePtr.append(ptr));
}
@Override
public int size(String path) {
return parent.size(basePtr.append(JsonPointer.compile(path)));
}
@Override
public String toString() {
JsonNode node;
try {
node = getObject(EMPTY_PTR, JsonNode.class);
} catch (CacheException e) {
LOGGER.error("", e);
node = null;
}
return "ChildCacheImpl [basePtr=" + basePtr + ", node=" + node + ']';
}
}
static class FactoryImpl implements Factory {
static final Factory instance = new FactoryImpl();
private final Map<String, JsonCacheImpl> instances = new HashMap<>();
@Override
public Root create() {
return new JsonCacheImpl();
}
@Override
public Root get(String key) {
synchronized (instances) {
JsonCacheImpl instance = instances.get(key);
if (instance == null) {
instance = new JsonCacheImpl();
instances.put(key, instance);
}
return instance;
}
}
}
protected static final JsonPointer EMPTY_PTR = JsonPointer.compile("/");
private static final Pattern INTEGER = Pattern.compile("^\\d+$");
protected static final Logger LOGGER = LoggerFactory.getLogger(JsonCacheImpl.class);
protected boolean isDirty;
protected boolean isLoaded;
protected ObjectMapper mapper;
protected MergePolicy mergePolicy = MergePolicy.MERGE_RECURSIVE;
protected ContainerNode<?> root;
private boolean shutdownHookRegistered;
protected JsonCacheImpl() {
mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
@Override
public JsonCache add(JsonPointer ptr, BigDecimal value) {
return add(ptr, nodeFor(value));
}
@Override
public JsonCache add(JsonPointer ptr, BigInteger value) {
return add(ptr, nodeFor(value));
}
@Override
public JsonCache add(JsonPointer ptr, boolean value) {
return add(ptr, nodeFor(value));
}
@Override
public JsonCache add(JsonPointer ptr, double value) {
return add(ptr, nodeFor(value));
}
@Override
public JsonCache add(JsonPointer ptr, float value) {
return add(ptr, nodeFor(value));
}
@Override
public JsonCache add(JsonPointer ptr, int value) {
return add(ptr, nodeFor(value));
}
protected JsonCache add(JsonPointer ptr, JsonNode node) {
// If ptr ends with an array index, this implies inserting at the specified index.
// If ptr does not end with an array index, this implies appending to the end of the array.
// In both cases the array in question and its ancestors must be created if they do not already exist.
String lastProperty = ptr.last().getMatchingProperty();
boolean isIndexed = isInteger(lastProperty);
ContainerNode<?> container = ensureContainerExists(ptr, !isIndexed);
switch (container.getNodeType()) {
case ARRAY:
ArrayNode array = (ArrayNode) container;
int index = isIndexed ? Integer.parseInt(lastProperty) : array.size();
if (index < array.size()) {
array.insert(index, node);
} else {
// Fill any gap between current size and index with nulls (Jackson doesn't support sparse arrays).
for (int i = array.size(); i < index; i++)
array.add(array.nullNode());
array.add(node);
}
break;
default:
throw new IllegalArgumentException(ptr + " does not identify an array");
}
setDirty();
return this;
}
@Override
public JsonCache add(JsonPointer ptr, long value) {
return add(ptr, nodeFor(value));
}
@Override
public JsonCache add(JsonPointer ptr, Object value) {
return add(ptr, nodeFor(value));
}
@Override
public JsonCache add(JsonPointer ptr, short value) {
return add(ptr, nodeFor(value));
}
@Override
public JsonCache add(String path, BigDecimal value) {
return add(JsonPointer.compile(path), value);
}
@Override
public JsonCache add(String path, BigInteger value) {
return add(JsonPointer.compile(path), value);
}
@Override
public JsonCache add(String path, boolean value) {
return add(JsonPointer.compile(path), value);
}
@Override
public JsonCache add(String path, double value) {
return add(JsonPointer.compile(path), value);
}
@Override
public JsonCache add(String path, float value) {
return add(JsonPointer.compile(path), value);
}
@Override
public JsonCache add(String path, int value) {
return add(JsonPointer.compile(path), value);
}
@Override
public JsonCache add(String path, long value) {
return add(JsonPointer.compile(path), value);
}
@Override
public JsonCache add(String path, Object value) {
return add(JsonPointer.compile(path), value);
}
@Override
public JsonCache add(String path, short value) {
return add(JsonPointer.compile(path), value);
}
@Override
public JsonCache child(JsonPointer basePtr) {
return new ChildCacheImpl(this, basePtr);
}
@Override
public JsonCache child(String path) {
return child(JsonPointer.compile(path));
}
@Override
public void delete(JsonPointer ptr) {
JsonPointer head = ptr.head();
if (head == null) {
root = null;
} else if (root != null) {
JsonNode parent = root.at(head);
if (parent.isArray()) {
((ArrayNode) parent).remove(Integer.parseInt(ptr.last().getMatchingProperty()));
} else if (parent.isObject()) {
((ObjectNode) parent).remove(ptr.last().getMatchingProperty());
} else {
throw new IllegalArgumentException(ptr + " does not identify a deletable node");
}
}
setDirty();
}
@Override
public void delete(String path) {
delete(JsonPointer.compile(path));
}
/**
* Ensures that a suitable container exists for the specified JSON pointer.
*
* @param ptr A <a href="https://tools.ietf.org/html/rfc6901">JSON Pointer</a> to the property to set.
* @return The container that owns the property identified by <code>path</code>.
*/
protected ContainerNode<?> ensureContainerExists(JsonPointer ptr) {
return ensureContainerExists(ptr, false);
}
/**
* Ensures that all ancestor containers exist for the specified JSON pointer.
*
* @param ptr A <a href="https://tools.ietf.org/html/rfc6901">JSON Pointer</a> to the property to set.
* @param forceArray <code>true</code> to create an array for the last segment of the pointer if it is non-integral.
* @return The container that owns the property identified by <code>path</code>.
*/
protected ContainerNode<?> ensureContainerExists(JsonPointer ptr, boolean forceArray) {
if (root == null) {
root = isInteger(ptr.getMatchingProperty()) // split
? JsonNodeFactory.instance.arrayNode()
: JsonNodeFactory.instance.objectNode();
}
String lastProperty = ptr.last().getMatchingProperty();
Deque<String> stack = new ArrayDeque<>();
JsonPointer ancestorPtr = forceArray && !isInteger(lastProperty) ? ptr : ptr.head();
JsonNode ancestor = root.at(ancestorPtr);
while (ancestor.isMissingNode()) {
stack.push(ancestorPtr.last().getMatchingProperty());
ancestorPtr = ancestorPtr.head();
ancestor = root.at(ancestorPtr);
}
if (!ancestor.isContainerNode())
throw new IllegalArgumentException(ancestorPtr + " does not identify a container node");
while (!stack.isEmpty()) {
String ancestorProperty = stack.pop();
String childProperty = stack.isEmpty() // split
? forceArray && !isInteger(lastProperty) // split
? "0" // split
: lastProperty // split
: stack.peek();
// Parent can be array or object; child can be array or object - that's four possible combinations.
// Infer the child container type from the child property name: an integer pattern implies an array node.
if (isInteger(childProperty)) {
switch (ancestor.getNodeType()) {
case ARRAY:
// ARRAY/ARRAY
ancestor = ((ArrayNode) ancestor).insertArray(Integer.parseInt(ancestorProperty));
break;
case OBJECT:
// OBJECT/ARRAY
ancestor = ((ObjectNode) ancestor).putArray(ancestorProperty);
break;
default:
throw new IllegalArgumentException(ancestorProperty + " does not identify an array node");
}
} else {
switch (ancestor.getNodeType()) {
case ARRAY:
// ARRAY/OBJECT
ancestor = ((ArrayNode) ancestor).insertObject(Integer.parseInt(ancestorProperty));
break;
case OBJECT:
// OBJECT/OBJECT
ancestor = ((ObjectNode) ancestor).putObject(ancestorProperty);
break;
default:
throw new IllegalArgumentException(ancestorProperty + " does not identify an array node");
}
}
setDirty();
}
return (ContainerNode<?>) ancestor;
}
@Override
public boolean exists(JsonPointer ptr) {
return root != null && !root.at(ptr).isMissingNode();
}
@Override
public boolean exists(String path) {
return exists(JsonPointer.compile(path));
}
@Override
public Root flush(File file) throws CacheException {
if (isDirty)
save(file);
return this;
}
@Override
public Root flush(OutputStream out) throws CacheException {
if (isDirty)
save(out);
return this;
}
@Override
public Root flushOnShutdown(final File file) {
if (!shutdownHookRegistered) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
try {
flush(file);
} catch (CacheException e) {
e.printStackTrace();
}
}
});
shutdownHookRegistered = true;
}
return this;
}
@Override
public Root flushOnShutdown(final OutputStream out) {
if (!shutdownHookRegistered) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
try {
flush(out);
} catch (CacheException e) {
e.printStackTrace();
}
}
});
shutdownHookRegistered = true;
}
return this;
}
@Override
public Object get(JsonPointer ptr) throws CacheException {
Object result;
if (root == null) {
result = null;
} else {
try {
JsonNode node = root.at(ptr);
switch (node.getNodeType()) {
case ARRAY:
case OBJECT:
result = node;
break;
case BINARY:
result = node.binaryValue();
break;
case BOOLEAN:
result = node.booleanValue();
break;
case NUMBER:
result = node.numberValue();
break;
case POJO:
result = ((POJONode) node).getPojo();
break;
case STRING:
result = node.textValue();
break;
default:
result = null;
break;
}
} catch (IOException e) {
throw new CacheException(e);
}
}
return result;
}
@Override
public Object get(JsonPointer ptr, Object defaultValue) throws CacheException {
Objects.requireNonNull(defaultValue, "defaultValue is required");
Object result;
if (exists(ptr)) {
result = get(ptr);
} else {
set(ptr, defaultValue);
result = defaultValue;
}
return result;
}
@Override
public Object get(String path) throws CacheException {
return get(JsonPointer.compile(path));
}
@Override
public Object get(String path, Object defaultValue) throws CacheException {
return get(JsonPointer.compile(path), defaultValue);
}
@Override
public BigDecimal getBigDecimal(JsonPointer ptr) {
return root == null ? null : root.at(ptr).decimalValue();
}
@Override
public BigDecimal getBigDecimal(JsonPointer ptr, BigDecimal defaultValue) throws CacheException {
Objects.requireNonNull(defaultValue, "defaultValue is required");
BigDecimal result;
if (exists(ptr)) {
result = getBigDecimal(ptr);
} else {
set(ptr, defaultValue);
result = defaultValue;
}
return result;
}
@Override
public BigDecimal getBigDecimal(String path) {
return getBigDecimal(JsonPointer.compile(path));
}
@Override
public BigDecimal getBigDecimal(String path, BigDecimal defaultValue) throws CacheException {
return getBigDecimal(JsonPointer.compile(path), defaultValue);
}
@Override
public BigInteger getBigInteger(JsonPointer ptr) {
return root == null ? null : root.at(ptr).bigIntegerValue();
}
@Override
public BigInteger getBigInteger(JsonPointer ptr, BigInteger defaultValue) throws CacheException {
Objects.requireNonNull(defaultValue, "defaultValue is required");
BigInteger result;
if (exists(ptr)) {
result = getBigInteger(ptr);
} else {
set(ptr, defaultValue);
result = defaultValue;
}
return result;
}
@Override
public BigInteger getBigInteger(String path) {
return getBigInteger(JsonPointer.compile(path));
}
@Override
public BigInteger getBigInteger(String path, BigInteger defaultValue) throws CacheException {
return getBigInteger(JsonPointer.compile(path), defaultValue);
}
@Override
public byte[] getBinary(JsonPointer ptr) throws CacheException {
try {
return root == null ? null : root.at(ptr).binaryValue();
} catch (IOException e) {
throw new CacheException(e);
}
}
@Override
public byte[] getBinary(JsonPointer ptr, byte[] defaultValue) throws CacheException {
Objects.requireNonNull(defaultValue, "defaultValue is required");
byte[] result;
if (exists(ptr)) {
result = getBinary(ptr);
} else {
set(ptr, defaultValue);
result = defaultValue;
}
return result;
}
@Override
public byte[] getBinary(String path) throws CacheException {
return getBinary(JsonPointer.compile(path));
}
@Override
public byte[] getBinary(String path, byte[] defaultValue) throws CacheException {
return getBinary(JsonPointer.compile(path), defaultValue);
}
@Override
public boolean getBoolean(JsonPointer ptr) {
return root != null && root.at(ptr).booleanValue();
}
@Override
public boolean getBoolean(JsonPointer ptr, boolean defaultValue) throws CacheException {
boolean result;
if (exists(ptr)) {
result = getBoolean(ptr);
} else {
set(ptr, defaultValue);
result = defaultValue;
}
return result;
}
@Override
public boolean getBoolean(String path) {
return getBoolean(JsonPointer.compile(path));
}
@Override
public boolean getBoolean(String path, boolean defaultValue) throws CacheException {
return getBoolean(JsonPointer.compile(path), defaultValue);
}
@Override
public double getDouble(JsonPointer ptr) {
return root == null ? 0.0D : root.at(ptr).doubleValue();
}
@Override
public double getDouble(JsonPointer ptr, double defaultValue) throws CacheException {
Objects.requireNonNull(defaultValue, "defaultValue is required");
double result;
if (exists(ptr)) {
result = getDouble(ptr);
} else {
set(ptr, defaultValue);
result = defaultValue;
}
return result;
}
@Override
public double getDouble(String path) {
return getDouble(JsonPointer.compile(path));
}
@Override
public double getDouble(String path, double defaultValue) throws CacheException {
return getDouble(JsonPointer.compile(path), defaultValue);
}
@Override
public float getFloat(JsonPointer ptr) {
return root == null ? 0.0F : root.at(ptr).floatValue();
}
@Override
public float getFloat(JsonPointer ptr, float defaultValue) throws CacheException {
float result;
if (exists(ptr)) {
result = getFloat(ptr);
} else {
set(ptr, defaultValue);
result = defaultValue;
}
return result;
}
@Override
public float getFloat(String path) {
return getFloat(JsonPointer.compile(path));
}
@Override
public float getFloat(String path, float defaultValue) throws CacheException {
return getFloat(JsonPointer.compile(path), defaultValue);
}
@Override
public int getInt(JsonPointer ptr) {
return root == null ? 0 : root.at(ptr).intValue();
}
@Override
public int getInt(JsonPointer ptr, int defaultValue) throws CacheException {
int result;
if (exists(ptr)) {
result = getInt(ptr);
} else {
set(ptr, defaultValue);
result = defaultValue;
}
return result;
}
@Override
public int getInt(String path) {
return getInt(JsonPointer.compile(path));
}
@Override
public int getInt(String path, int defaultValue) throws CacheException {
return getInt(JsonPointer.compile(path), defaultValue);
}
@Override
public long getLong(JsonPointer ptr) {
return root == null ? 0L : root.at(ptr).longValue();
}
@Override
public long getLong(JsonPointer ptr, long defaultValue) throws CacheException {
long result;
if (exists(ptr)) {
result = getLong(ptr);
} else {
set(ptr, defaultValue);
result = defaultValue;
}
return result;
}
@Override
public long getLong(String path) {
return getLong(JsonPointer.compile(path));
}
@Override
public long getLong(String path, long defaultValue) throws CacheException {
return getLong(JsonPointer.compile(path), defaultValue);
}
@Override
public ObjectMapper getMapper() {
return mapper;
}
@Override
public MergePolicy getMergePolicy() {
return mergePolicy;
}
@Override
public JsonNodeType getNodeType(JsonPointer ptr) {
return root.at(ptr).getNodeType();
}
@Override
public JsonNodeType getNodeType(String path) {
return getNodeType(JsonPointer.compile(path));
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
return super.hashCode();
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
return super.equals(obj);
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
@Override
protected void finalize() throws Throwable {
// TODO Auto-generated method stub
super.finalize();
}
@Override
public Number getNumber(JsonPointer ptr) {
return root == null ? null : root.at(ptr).numberValue();
}
@Override
public Number getNumber(JsonPointer ptr, Number defaultValue) throws CacheException {
Objects.requireNonNull(defaultValue, "defaultValue is required");
Number result;
if (exists(ptr)) {
result = getNumber(ptr);
} else {
set(ptr, defaultValue);
result = defaultValue;
}
return result;
}
@Override
public Number getNumber(String path) {
return getNumber(JsonPointer.compile(path));
}
@Override
public Number getNumber(String path, Number defaultValue) throws CacheException {
return getNumber(JsonPointer.compile(path), defaultValue);
}
@Override
public <T> T getObject(JsonPointer ptr, Class<T> type) throws CacheException {
T result;
if (root == null) {
result = null;
} else {
JsonNode node = root.at(ptr);
Object value = node.isPojo() && !JsonNode.class.isAssignableFrom(type) ? ((POJONode) node).getPojo() : node;
if ((value != null) && (value.getClass() == type)) {
result = (T) value;
} else {
result = mapper.convertValue(value, type);
}
}
return result;
}
@Override
@SuppressWarnings("unchecked")
public <T> T getObject(JsonPointer ptr, T defaultValue) throws CacheException {
Objects.requireNonNull(defaultValue, "defaultValue is required");
T result;
if (exists(ptr)) {
result = (T) getObject(ptr, defaultValue.getClass());
} else {
set(ptr, defaultValue);
result = defaultValue;
}
return result;
}
@Override
public <T> T getObject(String path, Class<T> type) throws CacheException {
return getObject(JsonPointer.compile(path), type);
}
@Override
public <T> T getObject(String path, T defaultValue) throws CacheException {
return getObject(JsonPointer.compile(path), defaultValue);
}
@Override
public <T> List<T> getObjects(JsonPointer ptr, Class<T> type) throws CacheException {
List<T> result;
if (root == null) {
result = null;
} else {
JsonNode node = root.at(ptr);
switch (node.getNodeType()) {
case ARRAY:
case OBJECT:
result = new ArrayList<T>(node.size());
Iterator<JsonNode> elements = node.elements();
while (elements.hasNext())
result.add(mapper.convertValue(elements.next(), type));
break;
default:
result = Collections.emptyList();
break;
}
}
return result;
}
@Override
public <T> List<T> getObjects(JsonPointer ptr, Class<T> type, List<T> defaultValue) throws CacheException {
Objects.requireNonNull(defaultValue, "defaultValue is required");
List<T> result;
if (exists(ptr)) {
result = getObjects(ptr, type);
} else {
set(ptr, defaultValue);
result = defaultValue;
}
return result;
}
@Override
public <T> List<T> getObjects(String path, Class<T> type) throws CacheException {
return getObjects(JsonPointer.compile(path), type);
}
@Override
public <T> List<T> getObjects(String path, Class<T> type, List<T> defaultValue) throws CacheException {
return getObjects(JsonPointer.compile(path), type, defaultValue);
}
@Override
public short getShort(JsonPointer ptr) {
return root == null ? (short) 0 : root.at(ptr).shortValue();
}
@Override
public short getShort(JsonPointer ptr, short defaultValue) {
short result;
if (exists(ptr)) {
result = getShort(ptr);
} else {
set(ptr, defaultValue);
result = defaultValue;
}
return result;
}
@Override
public short getShort(String path) {
return getShort(JsonPointer.compile(path));
}
@Override
public short getShort(String path, short defaultValue) {
return getShort(JsonPointer.compile(path), defaultValue);
}
@Override
public String getString(JsonPointer ptr) {
return root == null ? null : root.at(ptr).textValue();
}
@Override
public String getString(JsonPointer ptr, String defaultValue) {
Objects.requireNonNull(defaultValue, "defaultValue is required");
String result;
if (exists(ptr)) {
result = getString(ptr);
} else {
set(ptr, defaultValue);
result = defaultValue;
}
return result;
}
@Override
public String getString(String path) {
return getString(JsonPointer.compile(path));
}
@Override
public String getString(String path, String defaultValue) {
return getString(JsonPointer.compile(path), defaultValue);
}
protected void insertNumber(ArrayNode array, int index, Number value) {
if (value instanceof Short) {
array.insert(index, (Short) value);
} else if (value instanceof Integer) {
array.insert(index, (Integer) value);
} else if (value instanceof Long) {
array.insert(index, (Long) value);
} else if (value instanceof Float) {
array.insert(index, (Float) value);
} else if (value instanceof Double) {
array.insert(index, (Double) value);
} else if (value instanceof BigInteger) {
array.insert(index, (BigInteger) value);
} else if (value instanceof BigDecimal) {
array.insert(index, (BigDecimal) value);
} else {
throw new IllegalArgumentException(
"unsupported numeric value: " + value + " (" + value.getClass().getSimpleName() + ')');
}
}
@Override
public boolean isDirty() {
return isDirty;
}
protected boolean isInteger(String s) {
return INTEGER.matcher(s).matches();
}
@Override
public Root load(File file) throws CacheException {
Objects.requireNonNull(file, "file is required");
if (file.exists()) {
try (InputStream in = new FileInputStream(file)) {
load(in);
} catch (IOException e) {
throw new CacheException(e);
}
}
return this;
}
@Override
public Root load(InputStream in) throws CacheException {
Objects.requireNonNull(in, "in is required");
try (InputStream is = in) {
if (isLoaded) {
if (mergePolicy != MergePolicy.NO_MERGE) {
ContainerNode<?> tree = (ContainerNode<?>) mapper.readTree(in);
// The cache is already loaded, so merge the incoming object tree into the existing root.
merge(root, tree);
}
} else {
root = (ContainerNode<?>) mapper.readTree(in);
isDirty = false;
isLoaded = true;
}
} catch (IOException e) {
throw new CacheException(e);
}
return this;
}
@Override
public Root mapper(ObjectMapper mapper) {
Objects.requireNonNull(mapper, "mapper is required");
this.mapper = mapper;
return this;
}
protected void merge(ContainerNode<?> dest, ContainerNode<?> src) {
if (dest.getNodeType() == src.getNodeType()) {
if (dest.isArray()) {
ArrayNode destArray = (ArrayNode) dest;
ArrayNode srcArray = (ArrayNode) src;
outer:
for (int i = 0; i < srcArray.size(); i++) {
// Only add a source element if it is not already present in the destination array.
JsonNode srcElem = srcArray.get(i);
for (int j = 0; j < destArray.size(); j++) {
if (destArray.get(j).equals(srcElem))
continue outer;
}
destArray.add(srcElem);
}
} else if (dest.isObject()) {
ObjectNode destObject = (ObjectNode) dest;
ObjectNode srcObject = (ObjectNode) src;
Iterator<Entry<String, JsonNode>> fields = srcObject.fields();
while (fields.hasNext()) {
Entry<String, JsonNode> field = fields.next();
String fieldName = field.getKey();
JsonNode srcChild = field.getValue();
if (destObject.has(fieldName)) {
JsonNode destChild = destObject.get(fieldName);
switch (mergePolicy) {
case OVERWRITE_EXISTING:
destObject.set(fieldName, srcChild);
// Mark the cache as dirty as we've added items from another file.
isDirty = true;
LOGGER.info("Existing root property '{}' has been overwritten by incoming data",
fieldName);
break;
case MERGE_RECURSIVE:
if (destChild.isContainerNode() && srcChild.isContainerNode())
merge((ContainerNode<?>) destChild, (ContainerNode<?>) srcChild);
break;
case KEEP_EXISTING:
LOGGER.info("Existing root property '{}' will not be overwritten by incoming data",
fieldName);
default:
// Nothing to do.
break;
}
} else {
destObject.set(fieldName, srcChild);
LOGGER.info("New property '{}' has been added from incoming data", fieldName);
// Mark the cache as dirty as we've added items from another file.
isDirty = true;
}
}
}
} else {
LOGGER.warn("Cannot merge containers of differing types");
}
}
@Override
public Root mergePolicy(MergePolicy policy) {
Objects.requireNonNull(policy, "policy is required");
this.mergePolicy = policy;
return this;
}
// @Override
@SuppressWarnings("unchecked")
protected JsonNode nodeFor(Object value) {
JsonNode node;
if (value == null) {
node = root.nullNode();
} else if (value instanceof JsonNode) {
node = (JsonNode) value;
} else if (value instanceof Boolean) {
node = root.booleanNode((Boolean) value);
} else if (value instanceof List) {
node = root.arrayNode();
for (Object element : (List<?>) value)
((ArrayNode) node).add(nodeFor(element));
} else if (value instanceof Map) {
node = root.objectNode();
for (Entry<String, ?> entry : ((Map<String, ?>) value).entrySet())
((ObjectNode) node).set(entry.getKey(), nodeFor(entry.getValue()));
} else if (value instanceof Number) {
if (value instanceof Byte)
node = root.numberNode((Byte) value);
else if (value instanceof Short)
node = root.numberNode((Short) value);
else if (value instanceof Integer)
node = root.numberNode((Integer) value);
else if (value instanceof Long)
node = root.numberNode((Long) value);
else if (value instanceof Float)
node = root.numberNode((Float) value);
else if (value instanceof Double)
node = root.numberNode((Double) value);
else if (value instanceof BigInteger)
node = root.numberNode((BigInteger) value);
else if (value instanceof BigDecimal)
node = root.numberNode((BigDecimal) value);
else
throw new IllegalArgumentException("unsupported number type: " + value.getClass().getSimpleName());
} else if (value instanceof String) {
node = root.textNode((String) value);
} else if (value instanceof byte[]) {
node = root.binaryNode((byte[]) value);
} else {
node = root.pojoNode(value);
}
return node;
}
protected JsonNodeType nodeTypeFor(Object value) {
JsonNodeType type;
if (value == null) {
type = JsonNodeType.NULL;
} else if (value instanceof Boolean) {
type = JsonNodeType.BOOLEAN;
} else if (value instanceof Number) {
type = JsonNodeType.NUMBER;
} else if (value instanceof String) {
type = JsonNodeType.STRING;
} else if (value instanceof ArrayNode || value instanceof List) {
type = JsonNodeType.ARRAY;
} else if (value instanceof byte[]) {
type = JsonNodeType.BINARY;
} else if (value instanceof ObjectNode || value instanceof Map) {
type = JsonNodeType.OBJECT;
} else {
type = JsonNodeType.POJO;
}
return type;
}
@Override
public JsonCache parent() {
return null;
}
protected void putNumber(ObjectNode object, String property, Number value) {
if (value instanceof Short) {
object.put(property, (Short) value);
} else if (value instanceof Integer) {
object.put(property, (Integer) value);
} else if (value instanceof Long) {
object.put(property, (Long) value);
} else if (value instanceof Float) {
object.put(property, (Float) value);
} else if (value instanceof Double) {
object.put(property, (Double) value);
} else if (value instanceof BigInteger) {
object.put(property, (BigInteger) value);
} else if (value instanceof BigDecimal) {
object.put(property, (BigDecimal) value);
} else {
throw new IllegalArgumentException(
"unsupported numeric value: " + value + " (" + value.getClass().getSimpleName() + ')');
}
}
@Override
public Root root() {
return this;
}
@Override
public Root save(File file) throws CacheException {
Objects.requireNonNull(file, "file is required");
file.getParentFile().mkdirs();
try {
save(new FileOutputStream(file));
} catch (FileNotFoundException e) {
throw new CacheException(e);
}
return this;
}
@Override
public Root save(OutputStream out) throws CacheException {
if (root == null || root.isMissingNode())
throw new CacheException("null or missing root node");
Objects.requireNonNull(out, "out is required");
try (OutputStream o = out) {
mapper.writeValue(o, root);
} catch (IOException e) {
throw new CacheException(e);
}
isDirty = false;
return this;
}
@Override
public JsonCache set(JsonPointer ptr, BigDecimal value) {
return set(ptr, (Object) value);
}
@Override
public JsonCache set(JsonPointer ptr, BigInteger value) {
return set(ptr, (Object) value);
}
@Override
public JsonCache set(JsonPointer ptr, boolean value) {
return set(ptr, (Object) value);
}
@Override
public JsonCache set(JsonPointer ptr, double value) {
return set(ptr, (Object) value);
}
@Override
public JsonCache set(JsonPointer ptr, float value) {
return set(ptr, (Object) value);
}
@Override
public JsonCache set(JsonPointer ptr, int value) {
return set(ptr, (Object) value);
}
@Override
public JsonCache set(JsonPointer ptr, List<?> values) throws CacheException {
// Note: if the node identified by ptr is not an array, we must create one before populating it.
ArrayNode array;
ContainerNode<?> container = ensureContainerExists(ptr);
JsonNode target = container.at(ptr.last());
if (target.isArray()) {
array = (ArrayNode) target;
} else {
String property = ptr.last().getMatchingProperty();
array = container.arrayNode();
switch (container.getNodeType()) {
case ARRAY:
int index = Integer.parseInt(property);
((ArrayNode) container).set(index, array);
break;
case OBJECT:
((ObjectNode) container).set(property, array);
break;
default:
throw new CacheException(ptr + " does not identify an array");
}
}
// Now that the target array exists, we can populate it.
array.removeAll();
for (Object value : values) {
JsonNode node = nodeFor(value);
array.add(node);
}
setDirty();
return this;
}
@Override
public JsonCache set(JsonPointer ptr, long value) {
return set(ptr, (Object) value);
}
@Override
public JsonCache set(JsonPointer ptr, Object value) {
String property = ptr.last().getMatchingProperty();
ContainerNode<?> container = ensureContainerExists(ptr);
JsonNode node = nodeFor(value);
switch (container.getNodeType()) {
case ARRAY:
ArrayNode array = (ArrayNode) container;
int index = Integer.parseInt(property);
if (index < array.size()) {
array.set(index, node);
} else {
// Fill any gap between current size and index with nulls (Jackson doesn't support sparse arrays).
for (int i = array.size(); i < index; i++)
array.add(array.nullNode());
array.add(node);
}
break;
case OBJECT:
((ObjectNode) container).set(property, node);
break;
default:
throw new IllegalArgumentException(ptr + " does not identify a settable container");
}
setDirty();
return this;
}
@Override
public JsonCache set(JsonPointer ptr, short value) {
return set(ptr, (Object) value);
}
@Override
public JsonCache set(JsonPointer ptr, String value) {
return set(ptr, (Object) value);
}
@Override
public JsonCache set(String path, BigDecimal value) {
return set(JsonPointer.compile(path), value);
}
@Override
public JsonCache set(String path, BigInteger value) {
return set(JsonPointer.compile(path), value);
}
@Override
public JsonCache set(String path, boolean value) {
return set(JsonPointer.compile(path), value);
}
@Override
public JsonCache set(String path, double value) {
return set(JsonPointer.compile(path), value);
}
@Override
public JsonCache set(String path, float value) {
return set(JsonPointer.compile(path), value);
}
@Override
public JsonCache set(String path, int value) {
return set(JsonPointer.compile(path), value);
}
@Override
public JsonCache set(String path, List<?> values) throws CacheException {
return set(JsonPointer.compile(path), values);
}
@Override
public JsonCache set(String path, long value) {
return set(JsonPointer.compile(path), value);
}
@Override
public JsonCache set(String path, Object value) {
return set(JsonPointer.compile(path), value);
}
@Override
public JsonCache set(String path, short value) {
return set(JsonPointer.compile(path), value);
}
@Override
public JsonCache set(String path, String value) {
return set(JsonPointer.compile(path), value);
}
protected void setDirty() {
isDirty = true;
isLoaded = true;
}
@Override
public int size(JsonPointer ptr) {
return root == null ? 0 : root.at(ptr).size();
}
@Override
public int size(String path) {
return size(JsonPointer.compile(path));
}
@Override
public String toString() {
return "JsonCacheImpl [root=" + root + ']';
}
@Override
public Root unload() {
isLoaded = false;
isDirty = false;
root = null;
return this;
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.utils;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;
/**
* Utility class to convert Markdown (CommonMark) to HTML.
* <a href='https://github.com/atlassian/commonmark-java/issues/83'>This class is threadsafe.</a>
*/
public class Markdown {
// see https://github.com/atlassian/commonmark-java
private final Parser parser = Parser.builder().build();
private final HtmlRenderer renderer = HtmlRenderer.builder().build();
/**
* Convert input markdown text to HTML.
* Simple text is not wrapped in <p>...</p>.
* @param markdown text with Markdown styles. If <code>null</code>, <code>""</code> is returned.
* @return HTML rendering from the Markdown
*/
public String toHtml(String markdown) {
if (markdown == null)
return "";
Node document = parser.parse(markdown);
String html = renderer.render(document);
html = unwrapped(html);
return html;
}
// The CommonMark library wraps the HTML with
// <p> ... html ... </p>\n
// This method removes that markup wrapper if there are no other <p> elements,
// do that Markdown can be used in non-block contexts such as operation summary etc.
private static final String P_END = "</p>\n";
private static final String P_START = "<p>";
private String unwrapped(String html) {
if (html.startsWith(P_START) && html.endsWith(P_END)
&& html.lastIndexOf(P_START) == 0)
return html.substring(P_START.length(),
html.length() - P_END.length());
else
return html;
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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 com.ibizlab.codegen.utils;
import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList;
import java.util.List;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
public class OptionUtils {
public static List<Pair<String, String>> parseCommaSeparatedTuples(final String input) {
final List<Pair<String, String>> results = new ArrayList<Pair<String, String>>();
final List<String> tuples = splitCommaSeparatedList(input);
for (String tuple : tuples) {
int ix = tuple.indexOf('=');
if (ix > 0 && ix <= tuple.length() - 1) {
final Pair<String, String> pair = Pair.of(tuple.substring(0, ix), tuple.substring(ix + 1));
results.add(pair);
} else if (ix < 0){
final Pair<String, String> pair = Pair.of(tuple, "");
results.add(pair);
}
}
return results;
}
public static List<String> splitCommaSeparatedList(String input) {
List<String> results = new ArrayList<String>();
if(input != null && !input.isEmpty()) {
for (String value : input.split(",")) {
if(isNotEmpty(value))
results.add(value);
}
}
return results;
}
}
package com.ibizlab.codegen.utils;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Ticker;
import com.ibizlab.codegen.config.GlobalSettings;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class StringAdvUtils {
/**
* Set the cache size (entry count) of the sanitizedNameCache, camelizedWordsCache and underscoreWordsCache.
*/
public static final String NAME_CACHE_SIZE_PROPERTY = "com.ibizlab.codegen.utils.namecache.cachesize";
/**
* Set the cache expiry (in seconds) of the sanitizedNameCache, camelizedWordsCache and underscoreWordsCache.
*/
public static final String NAME_CACHE_EXPIRY_PROPERTY = "com.ibizlab.codegen.utils.namecache.expireafter.seconds";
// A cache of camelized words. The camelize() method is invoked many times with the same
// arguments, this cache is used to optimized performance.
private static Cache<Pair<String, Boolean>, String> camelizedWordsCache;
// A cache of underscored words, used to optimize the performance of the underscore() method.
private static Cache<String, String> underscoreWordsCache;
// A cache of escaped words, used to optimize the performance of the escape() method.
private static Cache<EscapedNameOptions, String> escapedWordsCache;
static {
int cacheSize = Integer.parseInt(GlobalSettings.getProperty(NAME_CACHE_SIZE_PROPERTY, "200"));
int cacheExpiry = Integer.parseInt(GlobalSettings.getProperty(NAME_CACHE_EXPIRY_PROPERTY, "5"));
camelizedWordsCache = Caffeine.newBuilder()
.maximumSize(cacheSize)
.expireAfterAccess(cacheExpiry, TimeUnit.SECONDS)
.ticker(Ticker.systemTicker())
.build();
escapedWordsCache = Caffeine.newBuilder()
.maximumSize(cacheSize)
.expireAfterAccess(cacheExpiry, TimeUnit.SECONDS)
.ticker(Ticker.systemTicker())
.build();
underscoreWordsCache = Caffeine.newBuilder()
.maximumSize(cacheSize)
.expireAfterAccess(cacheExpiry, TimeUnit.SECONDS)
.ticker(Ticker.systemTicker())
.build();
}
private static Pattern capitalLetterPattern = Pattern.compile("([A-Z]+)([A-Z][a-z][a-z]+)");
private static Pattern lowercasePattern = Pattern.compile("([a-z\\d])([A-Z])");
private static Pattern pkgSeparatorPattern = Pattern.compile("\\.");
private static Pattern dollarPattern = Pattern.compile("\\$");
/**
* Underscore the given word.
* Copied from Twitter elephant bird
* https://github.com/twitter/elephant-bird/blob/master/core/src/main/java/com/twitter/elephantbird/util/Strings.java
*
* @param word The word
* @return The underscored version of the word
*/
public static String underscore(final String word) {
return underscoreWordsCache.get(word, wordToUnderscore -> {
String result;
String replacementPattern = "$1_$2";
// Replace package separator with slash.
result = pkgSeparatorPattern.matcher(wordToUnderscore).replaceAll("/");
// Replace $ with two underscores for inner classes.
result = dollarPattern.matcher(result).replaceAll("__");
// Replace capital letter with _ plus lowercase letter.
result = capitalLetterPattern.matcher(result).replaceAll(replacementPattern);
result = lowercasePattern.matcher(result).replaceAll(replacementPattern);
result = result.replace('-', '_');
// replace space with underscore
result = result.replace(' ', '_');
result = result.toLowerCase(Locale.ROOT);
return result;
});
}
/**
* Dashize the given word.
*
* @param word The word
* @return The dashized version of the word, e.g. "my-name"
*/
public static String dashize(String word) {
return underscore(word).replaceAll("[_ ]+", "-");
}
/**
* Camelize name (parameter, property, method, etc) with upper case for first letter
* copied from Twitter elephant bird
* https://github.com/twitter/elephant-bird/blob/master/core/src/main/java/com/twitter/elephantbird/util/Strings.java
*
* @param word string to be camelize
* @return camelized string
*/
public static String camelize(String word) {
return camelize(word, false);
}
private static Pattern camelizeSlashPattern = Pattern.compile("\\/(.?)");
private static Pattern camelizeUppercasePattern = Pattern.compile("(\\.?)(\\w)([^\\.]*)$");
private static Pattern camelizeUnderscorePattern = Pattern.compile("(_)(.)");
private static Pattern camelizeHyphenPattern = Pattern.compile("(-)(.)");
private static Pattern camelizeDollarPattern = Pattern.compile("\\$");
private static Pattern camelizeSimpleUnderscorePattern = Pattern.compile("_");
/**
* Camelize name (parameter, property, method, etc)
*
* @param inputWord string to be camelize
* @param lowercaseFirstLetter lower case for first letter if set to true
* @return camelized string
*/
public static String camelize(final String inputWord, boolean lowercaseFirstLetter) {
Pair<String, Boolean> key = new ImmutablePair<>(inputWord, lowercaseFirstLetter);
return camelizedWordsCache.get(key, pair -> {
String word = pair.getKey();
Boolean lowerFirstLetter = pair.getValue();
// Replace all slashes with dots (package separator)
Matcher m = camelizeSlashPattern.matcher(word);
while (m.find()) {
word = m.replaceFirst("." + m.group(1)/*.toUpperCase()*/);
m = camelizeSlashPattern.matcher(word);
}
// case out dots
String[] parts = word.split("\\.");
StringBuilder f = new StringBuilder();
for (String z : parts) {
if (z.length() > 0) {
f.append(Character.toUpperCase(z.charAt(0))).append(z.substring(1));
}
}
word = f.toString();
m = camelizeSlashPattern.matcher(word);
while (m.find()) {
word = m.replaceFirst(Character.toUpperCase(m.group(1).charAt(0)) + m.group(1).substring(1)/*.toUpperCase()*/);
m = camelizeSlashPattern.matcher(word);
}
// Uppercase the class name.
m = camelizeUppercasePattern.matcher(word);
if (m.find()) {
String rep = m.group(1) + m.group(2).toUpperCase(Locale.ROOT) + m.group(3);
rep = camelizeDollarPattern.matcher(rep).replaceAll("\\\\\\$");
word = m.replaceAll(rep);
}
// Remove all underscores (underscore_case to camelCase)
m = camelizeUnderscorePattern.matcher(word);
while (m.find()) {
String original = m.group(2);
String upperCase = original.toUpperCase(Locale.ROOT);
if (original.equals(upperCase)) {
word = camelizeSimpleUnderscorePattern.matcher(word).replaceFirst("");
} else {
word = m.replaceFirst(upperCase);
}
m = camelizeUnderscorePattern.matcher(word);
}
// Remove all hyphens (hyphen-case to camelCase)
m = camelizeHyphenPattern.matcher(word);
while (m.find()) {
word = m.replaceFirst(m.group(2).toUpperCase(Locale.ROOT));
m = camelizeHyphenPattern.matcher(word);
}
if (lowerFirstLetter && word.length() > 0) {
int i = 0;
char charAt = word.charAt(i);
while (i + 1 < word.length() && !((charAt >= 'a' && charAt <= 'z') || (charAt >= 'A' && charAt <= 'Z'))) {
i = i + 1;
charAt = word.charAt(i);
}
i = i + 1;
word = word.substring(0, i).toLowerCase(Locale.ROOT) + word.substring(i);
}
// remove all underscore
word = camelizeSimpleUnderscorePattern.matcher(word).replaceAll("");
return word;
});
}
private static class EscapedNameOptions {
public EscapedNameOptions(String name, Set<String> specialChars, List<String> charactersToAllow, String appendToReplacement) {
this.name = name;
this.appendToReplacement = appendToReplacement;
if (specialChars != null) {
this.specialChars = Collections.unmodifiableSet(specialChars);
} else {
this.specialChars = Collections.emptySet();
}
if (charactersToAllow != null) {
this.charactersToAllow = Collections.unmodifiableList(charactersToAllow);
} else {
this.charactersToAllow = Collections.emptyList();
}
}
private String name;
private String appendToReplacement;
private Set<String> specialChars;
private List<String> charactersToAllow;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EscapedNameOptions that = (EscapedNameOptions) o;
return Objects.equals(name, that.name) &&
Objects.equals(appendToReplacement, that.appendToReplacement) &&
Objects.equals(specialChars, that.specialChars) &&
Objects.equals(charactersToAllow, that.charactersToAllow);
}
@Override
public int hashCode() {
return Objects.hash(name, appendToReplacement, specialChars, charactersToAllow);
}
}
/**
* Return the name with escaped characters.
*
* @param name the name to be escaped
* @param replacementMap map of replacement characters for non-allowed characters
* @param charactersToAllow characters that are not escaped
* @param appendToReplacement String to append to replaced characters.
* @return the escaped word
* <p>
* throws Runtime exception as word is not escaped properly.
*/
public static String escape(final String name, final Map<String, String> replacementMap,
final List<String> charactersToAllow, final String appendToReplacement) {
EscapedNameOptions ns = new EscapedNameOptions(name, replacementMap.keySet(), charactersToAllow, appendToReplacement);
return escapedWordsCache.get(ns, wordToEscape -> {
String result = name.chars().mapToObj(c -> {
String character = String.valueOf((char) c);
if (charactersToAllow != null && charactersToAllow.contains(character)) {
return character;
} else if (replacementMap.containsKey(character)) {
return replacementMap.get(character) + (appendToReplacement != null ? appendToReplacement: "");
} else {
return character;
}
}).reduce( (c1, c2) -> c1 + c2).orElse(null);
if (result != null) return result;
throw new RuntimeException("Word '" + name + "' could not be escaped.");
});
}
}
*volumes
*target
.settings
*node_modules
*bin
*.project
*.classpath
*.factorypath
.history
.vscode
.idea
**.iml
*.jar
*.log
.DS_Store
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>{{projectName}}</artifactId>
<groupId>{{packageName}}</groupId>
<version>1.0.0.0</version>
<name>{{projectDesc}}</name>
<description></description>
<packaging>pom</packaging>
<parent>
<groupId>{{packageName}}</groupId>
<artifactId>{{projectName}}-dependencies</artifactId>
<version>1.0.0.0</version>
<relativePath>{{projectName}}-dependencies/pom.xml</relativePath>
</parent>
<modules>
<!-- dependencies -->
<module>{{projectName}}-dependencies</module>
<!-- utils -->
<module>{{projectName}}-util</module>
<!-- cores -->
<module>{{projectName}}-core</module>
<!-- services -->
<module>{{projectName}}-provider</module>
<!-- apps -->
<module>{{projectName}}-app</module>
<!-- boot -->
<module>{{projectName}}-boot</module>
</modules>
<repositories>
<repository>
<id>aliyunmaven</id>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public/</url>
<layout>default</layout>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
</repositories>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>{{projectName}}</artifactId>
<groupId>{{packageName}}</groupId>
<version>1.0.0.0</version>
</parent>
<artifactId>{{projectName}}-app</artifactId>
<name>{{projectDesc}} Application</name>
<description>{{projectDesc}} Application</description>
<packaging>pom</packaging>
<modules>
<module>{{projectName}}-app-web</module>
</modules>
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>{{projectName}}</artifactId>
<groupId>{{packageName}}</groupId>
<version>1.0.0.0</version>
</parent>
<artifactId>{{projectName}}-boot</artifactId>
<name>{{projectDesc}} Dev Monolithic Boot</name>
<description>{{projectDesc}} Boot</description>
<dependencies>
<dependency>
<groupId>{{packageName}}</groupId>
<artifactId>{{projectName}}-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>{{packageName}}</groupId>
<artifactId>{{projectName}}-provider-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>{{packageName}}</groupId>
<artifactId>{{projectName}}-app-web</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<!--由于boot是通过dependency来关联所有子项目,页面和配置等信息都存在与子项目中,
所以您在对boot进行打包前,需要先将子项目install到maven仓库,以确保boot可以正常引用所有完整的子项目-->
<profiles>
<profile>
<id>boot</id>
<build>
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<includes>
<include>**/**</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<finalName>{{projectName}}</finalName>
<jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
<mainClass>{{packageName}}.DevBootApplication</mainClass>
<outputDirectory>../</outputDirectory>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>{{projectName}}</artifactId>
<groupId>{{packageName}}</groupId>
<version>1.0.0.0</version>
</parent>
<artifactId>{{projectName}}-core</artifactId>
<name>{{projectDesc}} Core</name>
<description>{{projectDesc}} Core</description>
<dependencies>
<dependency>
<groupId>{{packageName}}</groupId>
<artifactId>{{projectName}}-util</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<!-- JBPM -->
<dependency>
<groupId>org.jbpm</groupId>
<artifactId>jbpm-flow-builder</artifactId>
</dependency>
<dependency>
<groupId>org.jbpm</groupId>
<artifactId>jbpm-bpmn2</artifactId>
</dependency>
<!-- Drools -->
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-spring</artifactId>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!-- MySQL数据库 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Druid阿里连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<!--MapStruct高性能属性映射工具-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
</dependency>
<!--MongoDB-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!--Liquibase数据库版本更新工具-->
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
<!--baomidou-jobs定时服务 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>jobs-spring-boot-starter</artifactId>
</dependency>
</dependencies>
<properties>
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
</properties>
<profiles>
<profile>
<id>diff</id>
<build>
<plugins>
<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>${liquibase.version}</version>
<executions>
<execution>
<id>prepare-newdb</id>
<configuration>
<changeLogFile>${project.basedir}/src/main/resources/liquibase/h2_table.xml</changeLogFile>
<driver>org.h2.Driver</driver>
<url>jdbc:h2:file:${project.build.directory}/db/new;MODE=mysql</url>
<username>root</username>
<dropFirst>true</dropFirst>
</configuration>
<phase>process-resources</phase>
<goals>
<goal>update</goal>
</goals>
</execution>
<execution>
<id>prepare-olddb</id>
<configuration>
<changeLogFile>${project.basedir}/src/main/resources/liquibase/master_table.xml</changeLogFile>
<driver>org.h2.Driver</driver>
<url>jdbc:h2:file:${project.build.directory}/db/last;MODE=mysql</url>
<username>root</username>
<dropFirst>true</dropFirst>
</configuration>
<phase>process-resources</phase>
<goals>
<goal>update</goal>
</goals>
</execution>
<execution>
<id>make-diff</id>
<configuration>
<changeLogFile>${project.basedir}/src/main/resources/liquibase/empty.xml</changeLogFile>
<diffChangeLogFile>${project.basedir}/src/main/resources/liquibase/changelog/${maven.build.timestamp}_changelog.xml</diffChangeLogFile>
<driver>org.h2.Driver</driver>
<url>jdbc:h2:file:${project.build.directory}/db/last;MODE=mysql</url>
<username>root</username>
<password></password>
<referenceUrl>jdbc:h2:file:${project.build.directory}/db/new;MODE=mysql</referenceUrl>
<referenceDriver>org.h2.Driver</referenceDriver>
<referenceUsername>root</referenceUsername>
<verbose>true</verbose>
<logging>debug</logging>
<contexts>!test</contexts>
<diffExcludeObjects>Index:.*,table:ibzfile,ibzuser,ibzdataaudit,ibzcfg,IBZFILE,IBZUSER,IBZDATAAUDIT,IBZCFG</diffExcludeObjects>
</configuration>
<phase>process-resources</phase>
<goals>
<goal>diff</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
package {{packageName}}.{{module}}.domain;
public class {{entity.codeName}}
{
}
\ No newline at end of file
package {{packageName}}.{{entity.module}}.service;
public interface I{{entity.codeName}}Service
{
}
\ No newline at end of file
package {{packageName}}.{{entity.module}}.service.impl;
import {{packageName}}.{{entity.module}}.service.I{{entity.codeName}}Service;
public class {{entity.codeName}}ServiceImpl implements I{{entity.codeName}}Service
{
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ibizlab</groupId>
<artifactId>ibizlab-generator-project</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>ibizlab-generator-project</name>
<modules>
<module>modules/ibizlab-generator-core</module>
<module>modules/ibizlab-generator</module>
<module>modules/ibizlab-generator-cli</module>
</modules>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<lombok.version>1.18.12</lombok.version>
<checkstyle.plugin.version>3.1.0</checkstyle.plugin.version>
<commons-cli.version>1.4</commons-cli.version>
<commons-io.version>2.11.0</commons-io.version>
<commons-lang.version>3.12.0</commons-lang.version>
<diffutils.version>1.3.0</diffutils.version>
<generex.version>1.0.2</generex.version>
<git-commit-id-plugin.version>4.9.10</git-commit-id-plugin.version>
<groovy.version>3.0.9</groovy.version>
<guava.version>30.1.1-jre</guava.version>
<handlebars-java.version>4.2.1</handlebars-java.version>
<jackson-threetenbp.version>2.10.0</jackson-threetenbp.version>
<jacoco.version>0.8.7</jacoco.version>
<jmustache.version>1.14</jmustache.version>
<junit.version>4.13.2</junit.version>
<kotlin.version>1.3.60</kotlin.version>
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<maven-jar-plugin.version>3.2.0</maven-jar-plugin.version>
<maven-javadoc-plugin.version>3.1.1</maven-javadoc-plugin.version>
<maven-project-info-reports-plugin.version>3.0.0</maven-project-info-reports-plugin.version>
<maven-release-plugin.version>2.5.3</maven-release-plugin.version>
<maven-site-plugin.version>3.7.1</maven-site-plugin.version>
<mockito.version>3.12.4</mockito.version>
<pmd-plugin.version>3.12.0</pmd-plugin.version>
<reflections.version>0.10</reflections.version>
<rxgen.version>1.3</rxgen.version>
<scala-maven-plugin.version>4.3.1</scala-maven-plugin.version>
<slf4j.version>1.7.32</slf4j.version>
<spotbugs-plugin.version>3.1.12.2</spotbugs-plugin.version>
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
<swagger-core.version>2.1.2</swagger-core.version>
<swagger-parser-groupid.version>io.swagger.parser.v3</swagger-parser-groupid.version>
<swagger-parser.version>2.0.26</swagger-parser.version>
<testng.version>7.4.0</testng.version>
<violations-maven-plugin.version>1.34</violations-maven-plugin.version>
<wagon-ssh-external.version>3.4.3</wagon-ssh-external.version>
<wagon-svn.version>1.12</wagon-svn.version>
<wagon-webdav.version>1.0-beta-2</wagon-webdav.version>
<fastjson.version>1.2.76</fastjson.version>
<spring-framework.version>5.2.4.RELEASE</spring-framework.version>
<jackson.version>2.10.2</jackson.version>
</properties>
<repositories>
<repository>
<id>aliyunmaven</id>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public/</url>
<layout>default</layout>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
<repository>
<id>ibizmvnrepository</id>
<name>ibizmvnrepository</name>
<url>http://172.16.240.220:8081/nexus/content/groups/public/</url>
<layout>default</layout>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
</repositories>
</project>
\ No newline at end of file
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册