All Downloads are FREE. Search and download functionalities are using the official Maven repository.

objectos.code.Code Maven / Gradle / Ivy

/*
 * Copyright (C) 2014-2023 Objectos Software LTDA.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package objectos.code;

import java.util.function.Function;
import java.util.stream.Collectors;
import objectos.code.internal.CodeImpl;
import objectos.code.internal.CodeImportList;
import objectos.lang.Check;

/**
 * A {@linkplain StringTemplate.Processor string template processor} suitable
 * for generating Java source code.
 *
 * 

* In particular, it provides a facility for generating an import declaration * list based on all of the {@link ClassName} instances it processes. * *

* The following program generates the Java source code for a {@code HelloWorld} * class: * * {@snippet file = "objectos/code/JavadocSnippetsTest.java" region = "Code01"} * *

* When executed, the program prints: * *

{@code  package com.example;
 *
 * import java.util.List;
 *
 * public class HelloWorld {
 *   public static void main(String[] args) {
 *     List lines = List.of("Hello", "Objectos Code!");
 *     for (var line : lines) {
 *       System.out.println(line);
 *     }
 *   }
 * }}
*/ public sealed interface Code extends StringTemplate.Processor permits CodeImpl { /** * Provides the import list facility of the enclosing processor. An import * list instance is bound to a specific {@link Code} instance. The generated * list of import declarations are sorted alphabetically. * *

* This facility only supports single-type-import declarations. * *

Base package

* *

* An import list instance defines a base package. A {@link ClassName} * instance whose package name is different then the base package may * generate a single-type-import declaration. * *

* As an example, consider the following program: * * {@snippet file = "objectos/code/JavadocSnippetsTest.java" region = * "ImportList01"} * *

* When executed, it prints: * *

{@code  package com.example;
   *
   * import java.util.List;
   * import java.time.LocalDate;
   *
   * interface Example01 {
   *   List strings();
   *   LocalDate localDate();
   * }}
* *

{@code java.lang} types and base package types

* * {@link ClassName} instances whose package name are either: * *
    *
  • {@code java.lang}; or *
  • the base package. *
* * Will not generate an import declaration and, usually, will be * emitted only with its simple name. * *

* As an example, consider the following program: * * {@snippet file = "objectos/code/JavadocSnippetsTest.java" region = * "ImportList02"} * *

* When executed, it prints: * *

{@code  package com.example;
   *
   * interface Example02 {
   *   Thread thread();
   *   Foo foo();
   * }}
* *

Same simple name but different package names and/or enclosing * types

* *

* The import list facility handles conflicts that arise when different types * have the same simple name. * *

* To illustrate, consider the following program: * * {@snippet file = "objectos/code/JavadocSnippetsTest.java" region = * "ImportList03"} * *

* When executed, it prints: * *

{@code  package com.example;
   *
   * import java.util.List;
   *
   * interface Example03 {
   *   List list01();
   *   com.example.List list02();
   *   java.awt.List list03();
   * }}
*/ public sealed interface ImportList permits CodeImportList {} /** * Returns a newly created {@code Code} instance. * * @return a new {@code Code} instance */ static Code of() { return new CodeImpl(); } /** * Escapes the specified string so it can be used to represent the value of a * Java string literal. * *

* The following program uses a text block value to generate the value of a * string literal: * * {@snippet file = "objectos/code/JavadocSnippetsTest.java" region = * "Code-escape"} * *

* When executed, the program prints: * *

   * String asStringLiteral = "An \"escape\" function\nexample!\n";
* * @param str * the string to be escaped * * @return the escaped string */ static String escape(String str) { // implicit null check int length; length = str.length(); StringBuilder sb; sb = new StringBuilder(length); for (int i = 0; i < length; i++) { char c = str.charAt(i); switch (c) { case '\\' -> sb.append("\\\\"); case '\"' -> sb.append("\\\""); case '\b' -> sb.append("\\b"); case '\t' -> sb.append("\\t"); case '\n' -> sb.append("\\n"); case '\f' -> sb.append("\\f"); case '\r' -> sb.append("\\r"); default -> sb.append(c); } } return sb.toString(); } /** * Increases the indentation of each line of the specified string based on the * value of {@code n}. * *

* It behaves similarly to invoking the method {@linkplain String#indent(int) * String::indent} directly on the specified string {@code str} with the * following differences: * *

    *
  • this method rejects values of {@code n} which are non-positive; *
  • lines which are blank are ignored; and *
  • a new line character is not added to the end of the result. *
* * @param str * the string to have the indentation increases * @param n * number of leading white space characters to add * * @return string with indentation increased * * @throws IllegalArgumentException * if {@code n <= 0} */ static String indent(String str, int n) { Check.argument(n > 0, "n must be a positive number"); // implicit null-check if (str.isEmpty()) { return ""; } final String spaces; spaces = " ".repeat(n); Function mapper; mapper = s -> { if (!s.isBlank()) { s = spaces + s; } return s; }; return str.lines().map(mapper).collect(Collectors.joining("\n")); } /** * Return the import list facility bound to this processor using the specified * package name as its base package. * *

* In other words, the returned import list will usually not generate an * import declaration for a type whose package is the same as the specified * {@code packageName}. * *

* Invoking this method also clears all of the previously processed * {@link ClassName} instances by the returned import list. * * @param packageName * the name of the package for whose types an import declaration should * not be generated (if possible). * * @return the import list instance bound to this processor * * @throws IllegalArgumentException * if {@code packageName} is not a valid identifier */ ImportList importList(String packageName); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy