+ * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *
+ * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +module jisel { + exports org.jisel; + requires java.compiler; + requires java.logging; + requires com.google.auto.service; +} \ No newline at end of file diff --git a/src/main/java/org/jisel/AddToProfile.java b/src/main/java/org/jisel/AddToProfile.java index 81bd070..db8d434 100644 --- a/src/main/java/org/jisel/AddToProfile.java +++ b/src/main/java/org/jisel/AddToProfile.java @@ -1,3 +1,24 @@ +/** + * Copyright (c) 2022 Mohamed Ashraf Bayor + *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *
+ * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
package org.jisel;
import java.lang.annotation.ElementType;
@@ -6,16 +27,48 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import static org.jisel.generator.StringGenerator.EMPTY_STRING;
+
+/**
+ * Annotation to be applied on top of a class, an interface or a record which is implementing or extending a sealed interface generated by Jisel.
+ * All sealed interfaces generated by Jisel follow the naming convention: Sealed<ProfileName><LargeInterfaceSimpleName>
+ * See @{@link AddToProfile} attributes documentation.
+ */
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE})
-@Repeatable(AddToProfile.AddToProfiless.class)
+@Repeatable(AddToProfile.AddToProfilez.class)
public @interface AddToProfile {
- String value();
+ /**
+ * Not Required - specifies the name of one of the profiles used with the @SealForProfile annotations in the large interface definition.
+ * Also corresponds to the <ProfileName> from the sealed interfaces naming convention.
+ * If not provided or empty, the annotated class, interface or record will be added to the permits list of the generated parent sealed interface.
+ * Also, the provided profile attribute value MUST be one of the profiles defined in the large interface definition using @SealForProfile. If not,
+ * the specified profile will be ignored and an informational message regarding provided incorrect profiles will be printed during the compilation.
+ *
+ * @return the profile name
+ */
+ String profile() default EMPTY_STRING;
+
+ /**
+ * Required - MUST be the Fully Qualified Name of the large interface. That would be the <LargeInterfaceSimpleName> as seen in
+ * the sealed interface name convention, preceded by the package name.
+ *
+ * @return the large interface fully qualified name
+ */
+ String largeInterface();
+ /**
+ * Internal annotation allowing @AddToProfile to be repeatable
+ */
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
- @interface AddToProfiless {
+ @interface AddToProfilez {
+ /**
+ * array attribute allowing @{@link AddToProfile} to be repeatable
+ *
+ * @return array of @AddToProfile instances
+ */
AddToProfile[] value();
}
}
\ No newline at end of file
diff --git a/src/main/java/org/jisel/AddToProfiles.java b/src/main/java/org/jisel/AddToProfiles.java
index c89af8b..4a7d201 100644
--- a/src/main/java/org/jisel/AddToProfiles.java
+++ b/src/main/java/org/jisel/AddToProfiles.java
@@ -1,12 +1,74 @@
+/**
+ * Copyright (c) 2022 Mohamed Ashraf Bayor
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *
+ * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
package org.jisel;
import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import static org.jisel.generator.StringGenerator.EMPTY_STRING;
+
+/**
+ * Annotation to be applied on top of a class, an interface or a record which is implementing or extending a sealed interface generated by Jisel.
+ * All sealed interfaces generated by Jisel follow the naming convention: Sealed<ProfileName><LargeInterfaceSimpleName>
+ * See @{@link AddToProfiles} attributes documentation.
+ */
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE})
+@Repeatable(AddToProfiles.AddToProfilezz.class)
public @interface AddToProfiles {
- String[] value();
+
+ /**
+ * Not Required - specifies an array containing the names of any of the profiles used with the @{@link SealForProfile} annotations in the large interface definition.
+ * Each one of the profiles names corresponds to the <ProfileName> from the sealed interfaces naming convention.
+ * If not provided or empty, the annotated class, interface or record will be added to the permits list of the generated parent sealed interface.
+ * Also, each one of the provided profiles names MUST be one of the profiles defined in the large interface definition using @SealForProfile. If not,
+ * the specified profile will be ignored and an informational message regarding provided incorrect profiles will be printed during the compilation.
+ *
+ * @return an array of the profiles names
+ */
+ String[] profiles() default EMPTY_STRING;
+
+ /**
+ * Required - MUST be the Fully Qualified Name of the large interface. That would be the <LargeInterfaceSimpleName> as seen
+ * in the sealed interface name convention, preceded by the package name.
+ *
+ * @return the large interface fully qualified name
+ */
+ String largeInterface();
+
+ /**
+ * Internal annotation allowing @{@link AddToProfiles} to be repeatable
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @Target(ElementType.TYPE)
+ @interface AddToProfilezz {
+ /**
+ * array attribute allowing @{@link AddToProfiles} to be repeatable
+ *
+ * @return array of @AddToProfiles instances
+ */
+ AddToProfiles[] value();
+ }
}
\ No newline at end of file
diff --git a/src/main/java/org/jisel/JiselAnnotationProcessor.java b/src/main/java/org/jisel/JiselAnnotationProcessor.java
index 89890cf..f54981b 100644
--- a/src/main/java/org/jisel/JiselAnnotationProcessor.java
+++ b/src/main/java/org/jisel/JiselAnnotationProcessor.java
@@ -1,6 +1,32 @@
+/**
+ * Copyright (c) 2022 Mohamed Ashraf Bayor
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *
+ * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
package org.jisel;
import com.google.auto.service.AutoService;
+import org.jisel.generator.SealedInterfaceSourceFileGenerator;
+import org.jisel.generator.StringGenerator;
+import org.jisel.handlers.AddToProfileHandler;
+import org.jisel.handlers.JiselAnnotationHandler;
+import org.jisel.handlers.SealForProfileHandler;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
@@ -9,95 +35,122 @@
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
-import javax.tools.JavaFileObject;
import java.io.IOException;
-import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-
-// @Slf4j
-@SupportedAnnotationTypes("com.bayor.jisel.annotation.SealFor")
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import static java.lang.String.format;
+import static java.util.Collections.unmodifiableMap;
+import static java.util.Collections.unmodifiableSet;
+import static java.util.stream.Collectors.joining;
+import static org.jisel.generator.StringGenerator.ORG_JISEL_ADD_TO_PROFILE;
+import static org.jisel.generator.StringGenerator.ORG_JISEL_ADD_TO_PROFILES;
+import static org.jisel.generator.StringGenerator.ORG_JISEL_ADD_TO_PROFILEZ;
+import static org.jisel.generator.StringGenerator.ORG_JISEL_ADD_TO_PROFILEZZ;
+import static org.jisel.generator.StringGenerator.ORG_JISEL_SEAL_FOR_PROFILE;
+import static org.jisel.generator.StringGenerator.ORG_JISEL_SEAL_FOR_PROFILES;
+import static org.jisel.generator.StringGenerator.ORG_JISEL_SEAL_FOR_PROFILEZ;
+import static org.jisel.generator.StringGenerator.ORG_JISEL_SEAL_FOR_PROFILEZZ;
+
+/**
+ * Jisel annotation processor class. Picks up and processes all elements annotated with @{@link SealForProfile}, @{@link SealForProfiles}, @{@link AddToProfile} and @{@link AddToProfiles}
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
package org.jisel;
import java.lang.annotation.ElementType;
@@ -6,16 +27,37 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+/**
+ * Annotation to be applied only on top of abstract methods of an interface you intend to segregate.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
package org.jisel;
import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+/**
+ * Annotation to be applied only on top of abstract methods of an interface you intend to segregate.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.jisel.generator;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.type.ExecutableType;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static java.lang.String.format;
+import static java.util.Arrays.asList;
+import static java.util.stream.Collectors.joining;
+
+/**
+ * Exposes contract to be fulfilled by a class generating the code of a sealed interface
+ */
+public sealed interface CodeGenerator permits JavaxGeneratedGenerator, ExtendsGenerator, PermitsGenerator, MethodsGenerator {
+
+ /**
+ * Generates piece of code requested, based on the parameters provided in the params object and appends it to the provided classOrInterfaceContent param
+ *
+ * @param classOrInterfaceContent Stringbuilder object containing the sealed interface code being generated
+ * @param params expected parameters
+ */
+ void generateCode(StringBuilder classOrInterfaceContent, List
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.jisel.generator;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.TypeElement;
+import java.util.List;
+import java.util.Map;
+
+import static java.lang.String.format;
+import static java.util.Arrays.asList;
+import static java.util.stream.Collectors.toSet;
+
+/**
+ * Generates content for a final class.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -19,21 +19,20 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-package org.jisel.generator.helpers;
+package org.jisel.generator;
import org.jisel.JiselAnnotationProcessor;
import java.io.IOException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
-import java.util.Map;
+import java.util.List;
import java.util.Properties;
import static java.lang.String.format;
/**
- * Generates the @javax.annotation.processing.Generated annotation section at the top of the generated record class with the attributes: value, date and comments
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.jisel.generator;
+
+import javax.lang.model.element.Element;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import static java.lang.String.format;
+import static java.util.stream.Collectors.joining;
+
+/**
+ * Generates a Report file listing all generated sealed interfaces for the provided large interfaces.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.jisel.generator;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import static java.lang.String.format;
+
+/**
+ * Generates the content of a sealed interface
+ */
+public final class SealedInterfaceContentGenerator implements StringGenerator {
+
+ private final CodeGenerator javaxGeneratedGenerator;
+ private final ExtendsGenerator extendsGenerator;
+ private final PermitsGenerator permitsGenerator;
+ private final MethodsGenerator methodsGenerator;
+
+ /**
+ * SealedInterfaceContentGenerator constructor. Instantiates needed instances of {@link JavaxGeneratedGenerator}, {@link SealedInterfaceExtendsGenerator},
+ * {@link SealedInterfacePermitsGenerator} and {@link SealedInterfaceMethodsGenerator}
+ */
+ public SealedInterfaceContentGenerator() {
+ this.javaxGeneratedGenerator = new JavaxGeneratedGenerator();
+ this.extendsGenerator = new SealedInterfaceExtendsGenerator();
+ this.permitsGenerator = new SealedInterfacePermitsGenerator();
+ this.methodsGenerator = new SealedInterfaceMethodsGenerator();
+ }
+
+ /**
+ * Generates the content of a sealed interface
+ *
+ * @param processingEnvironment {@link ProcessingEnvironment} object, needed to access low-level information regarding the used annotations
+ * @param sealedInterfacesToGenerateMapEntrySet {@link java.util.Map.Entry} instance containing information about the sealed interfaces to be generated
+ * @param largeInterfaceElement {@link Element} instance of the large interface being segregated
+ * @param sealedInterfacesPermitsMap Map containing information about the subtypes permitted by each one of the sealed interfaces to be generated
+ * @return the string content of the sealed interface to generate
+ */
+ public String generateSealedInterfaceContent(final ProcessingEnvironment processingEnvironment,
+ final Map.Entry
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
package org.jisel.generator;
-public class SealedInterfaceSourceFileGenerator {
-}
+import javax.annotation.processing.FilerException;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.tools.StandardLocation;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Creates the content of a sealed interface and writes it to the filesystem.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.jisel.generator;
+
+import javax.lang.model.element.Element;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.UnaryOperator;
+
+import static java.lang.String.format;
+import static java.util.Arrays.asList;
+import static java.util.stream.Collectors.joining;
+
+/**
+ * A bunch of String literals and commonly used string handling functions
+ */
+public interface StringGenerator {
+
+ /**
+ * "," comma separator
+ */
+ String COMMA_SEPARATOR = ",";
+ /**
+ * ";" semi-colon
+ */
+ String SEMICOLON = ";";
+ /**
+ * " " whitespace
+ */
+ String WHITESPACE = " ";
+ /**
+ * "Sealed"
+ */
+ String SEALED_PREFIX = "Sealed";
+ /**
+ * "package"
+ */
+ String PACKAGE = "package";
+ /**
+ * "interface"
+ */
+ String INTERFACE = "interface";
+ /**
+ * "class"
+ */
+ String CLASS = "class";
+ /**
+ * "public sealed interface"
+ */
+ String PUBLIC_SEALED_INTERFACE = "public sealed interface";
+ /**
+ * "public final class"
+ */
+ String PUBLIC_FINAL_CLASS = "public final class";
+ /**
+ * "extends"
+ */
+ String EXTENDS = "extends";
+ /**
+ * "implements"
+ */
+ String IMPLEMENTS = "implements";
+ /**
+ * "permits"
+ */
+ String PERMITS = "permits";
+ /**
+ * "{"
+ */
+ String OPENING_BRACKET = "{";
+ /**
+ * "}"
+ */
+ String CLOSING_BRACKET = "}";
+ /**
+ * "("
+ */
+ String OPENING_PARENTHESIS = "(";
+ /**
+ * ")"
+ */
+ String CLOSING_PARENTHESIS = ")";
+ /**
+ * ""
+ */
+ String EMPTY_STRING = "";
+ /**
+ * "."
+ */
+ String DOT = ".";
+ /**
+ * "param"
+ */
+ String PARAMETER_PREFIX = "param";
+ /**
+ * "@"
+ */
+ String TEMP_PLACEHOLDER = "@";
+ /**
+ * "_"
+ */
+ String UNDERSCORE = "_";
+ /**
+ * "FinalClass"
+ */
+ String FINAL_CLASS_SUFFIX = "FinalCass";
+ /**
+ * "return"
+ */
+ String RETURN = "return";
+ /**
+ * "java.lang.Object"
+ */
+ String JAVA_LANG_OBJECT = "java.lang.Object";
+
+ /**
+ * "SealForProfile"
+ */
+ String SEAL_FOR_PROFILE = "SealForProfile";
+ /**
+ * "AddToProfile"
+ */
+ String ADD_TO_PROFILE = "AddToProfile";
+ /**
+ * Regex expression to read the string value of the "profile" attribute
+ */
+ String PROFILE_ATTRIBUTE_REGEX = "profile=\"([^\"]*)\"";
+ /**
+ * Regex expression to read the string value of the "largeInterface" attribute
+ */
+ String LARGE_INTERFACE_ATTRIBUTE_REGEX = "largeInterface=\"([^\"]*)\"";
+ /**
+ * Regex expression to read any attribute value provided within ""
+ */
+ String ANNOTATION_VALUES_REGEX = "\"([^\"]*)\"";
+ /**
+ * Regex expression to read attributes information provided using the {@link org.jisel.AddToProfile} annotation.
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package org.jisel.generator.helpers;
-
-import java.util.Map;
-
-/**
- * Exposes contract for a CodeGenerator class to fulfill
- */
-public sealed interface CodeGenerator permits JavaxGeneratedGenerator {
-
- // List of the parameters expected in the params Map object of the generateCode method:
-
- /**
- * parameter name: "qualifiedClassName", expected type: String
- */
- String QUALIFIED_CLASS_NAME = "qualifiedClassName";
-
- /**
- * parameter name: "fieldName", expected type: String
- */
- String FIELD_NAME = "fieldName";
-
- /**
- * parameter name: "getterReturnType", expected type: String
- */
- String GETTER_RETURN_TYPE = "getterReturnType";
-
- /**
- * parameter name: "getterAsString", expected type: String
- */
- String GETTER_AS_STRING = "getterAsString";
-
- /**
- * parameter name: "gettersList", expected type: List<? extends javax.lang.model.element.Element>, ex:[getLastname(), getAge(), getMark(), getGrade(), getSchool()]
- */
- String GETTERS_LIST = "gettersList";
-
- /**
- * parameter name: "gettersMap", expected type: Map<String, String>, ex: {getAge=int, getSchool=org.froporec.data1.School, getLastname=java.lang.String}
- */
- String GETTERS_MAP = "gettersMap";
-
- /**
- * Generates piece of code requested, based on the parameters provided in the params object and appends it to the provided recordClassContent param
- * @param recordClassContent Stringbuilder object containing the record class code being generated
- * @param params expected parameters. restricted to what is expected by the implementing class. the expected parameters names are defined as constants in the CodeGenerator interface.
- */
- void generateCode(StringBuilder recordClassContent, Map
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.jisel.handlers;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import static java.util.Arrays.asList;
+import static java.util.stream.Collectors.toSet;
+import static java.util.stream.Stream.concat;
+
+/**
+ * Handles all elements annotated with @{@link org.jisel.AddToProfile}
+ */
+public final class AddToProfileHandler implements JiselAnnotationHandler {
+
+ @Override
+ public Map
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.jisel.handlers;
+
+import org.jisel.generator.StringGenerator;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import static java.util.Arrays.asList;
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toMap;
+import static java.util.stream.Collectors.toSet;
+import static java.util.stream.Stream.concat;
+import static org.jisel.generator.StringGenerator.removeCommaSeparator;
+
+/**
+ * Exposes contract to fulfill by any class handling all elements annotated with @{@link org.jisel.SealForProfile}(s) and @{@link org.jisel.AddToProfile}(s) annotations
+ */
+public sealed interface JiselAnnotationHandler extends StringGenerator permits SealForProfileHandler, AddToProfileHandler,
+ AnnotationInfoCollectionHandler, UniqueParentInterfaceHandler, ParentChildInheritanceHandler {
+
+ /**
+ * Reads values of all attributes provided through the use of @{@link org.jisel.SealForProfile} and @{@link org.jisel.AddToProfile} annotations and
+ * populates the provided Map arguments
+ *
+ * @param processingEnv {@link ProcessingEnvironment} object, needed to access low-level information regarding the used annotations
+ * @param allAnnotatedElements {@link Set} of {@link Element} instances representing all classes annotated with @AddToProfile and
+ * all abstract methods annotated with @SealForProfile
+ * @param sealedInterfacesToGenerateByLargeInterface Map containing information about the sealed interfaces to be generated.
+ * To be populated and/or modified if needed. The key represents the Element instance of
+ * each one of the large interfaces to be segregated, while the associated value is
+ * a Map of profile name as the key and a Set of Element instances as the value.
+ * The Element instances represent each one of the abstract methods to be
+ * added to the generated sealed interface corresponding to a profile.
+ * @param sealedInterfacesPermitsByLargeInterface Map containing information about the subtypes permitted by each one of the sealed interfaces to be generated.
+ * To be populated and/or modified if needed. The key represents the Element instance of
+ * each one of the large interfaces to be segregated, while the associated value is
+ * a Map of profile name as the key and a List of profiles names as the value.
+ * @return a status report as a string value for each one of the large interfaces to be segregated
+ */
+ Map
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.jisel.handlers;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.toSet;
+import static java.util.stream.Stream.concat;
+
+/**
+ * Handles all elements annotated with @{@link org.jisel.SealForProfile}
+ */
+public final class SealForProfileHandler implements JiselAnnotationHandler {
+
+ private final AnnotationInfoCollectionHandler annotationInfoCollectionHandler;
+ private final UniqueParentInterfaceHandler uniqueParentInterfaceHandler;
+ private final ParentChildInheritanceHandler parentChildInheritanceHandler;
+
+ /**
+ * SealForProfileHandler constructor. Instantiates needed instances of {@link SealForProfileInfoCollectionHandler},
+ * {@link SealForProfileUniqueParentInterfaceHandler} and {@link SealForProfileParentChildInheritanceHandler}
+ */
+ public SealForProfileHandler() {
+ this.annotationInfoCollectionHandler = new SealForProfileInfoCollectionHandler();
+ this.uniqueParentInterfaceHandler = new SealForProfileUniqueParentInterfaceHandler();
+ this.parentChildInheritanceHandler = new SealForProfileParentChildInheritanceHandler();
+ }
+
+ @Override
+ public Map
+ */
+@SupportedAnnotationTypes({ORG_JISEL_SEAL_FOR_PROFILE, ORG_JISEL_SEAL_FOR_PROFILES, ORG_JISEL_SEAL_FOR_PROFILEZ, ORG_JISEL_SEAL_FOR_PROFILEZZ,
+ ORG_JISEL_ADD_TO_PROFILE, ORG_JISEL_ADD_TO_PROFILES, ORG_JISEL_ADD_TO_PROFILEZ, ORG_JISEL_ADD_TO_PROFILEZZ})
@SupportedSourceVersion(SourceVersion.RELEASE_17)
@AutoService(Processor.class)
-public class JiselAnnotationProcessor extends AbstractProcessor {
-
- @Override
- public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnvironment) {
-
- for (TypeElement annotation : annotations) {
-
- if (!annotation.getSimpleName().toString().contains("SealFor"))
- continue;
+public class JiselAnnotationProcessor extends AbstractProcessor implements StringGenerator {
- Set extends Element> annotatedElements = roundEnvironment.getElementsAnnotatedWith(annotation);
+ private final Logger log = Logger.getLogger(JiselAnnotationProcessor.class.getName());
- System.out.println(">>>>>>>> annotatedElements >>>>>>>>>>>" + annotatedElements);
+ private final JiselAnnotationHandler sealForProfileHandler;
- List extends Element> annotatedClasses = annotatedElements.stream()
- //.filter(element -> element.getClass().getClassLoader().isRecord())
- .filter(element -> ElementKind.INTERFACE.equals(element.getKind()))
- .toList();
+ private final JiselAnnotationHandler addToProfileHandler;
- System.out.println(">>>>>>>> annotatedClasses >>>>>>>>>>>" + annotatedClasses);
+ private final SealedInterfaceSourceFileGenerator sealedInterfaceSourceFileGenerator;
- List extends Element> annotatedMethods = annotatedElements.stream()
- .filter(element -> !element.getClass().isRecord())
- .filter(element -> ElementKind.METHOD.equals(element.getKind()))
- .toList();
+ /**
+ * JiselAnnotationProcessor constructor. Initializes needed instances of {@link SealForProfileHandler}, {@link AddToProfileHandler} and {@link SealedInterfaceSourceFileGenerator}
+ */
+ public JiselAnnotationProcessor() {
+ this.sealForProfileHandler = new SealForProfileHandler();
+ this.addToProfileHandler = new AddToProfileHandler();
+ this.sealedInterfaceSourceFileGenerator = new SealedInterfaceSourceFileGenerator();
+ }
- System.out.println(">>>>>>>> annotateMethods >>>>>>>>>>>" + annotatedMethods);
+ @Override
+ public boolean process(final Set extends TypeElement> annotations, final RoundEnvironment roundEnv) {
+
+ var allAnnotatedSealForProfileElements = new HashSet
+ * For the specified profile name, a sealed interface will be generated following the naming convention:
+ * Sealed<ProfileName><LargeInterfaceSimpleName>
+ * <LargeInterfaceSimpleName> corresponds to the simplename of the interface being segregated.
+ * See @{@link SealForProfile} attributes documentation.
+ */
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.METHOD})
-@Repeatable(SealForProfile.SealForProfiless.class)
+@Repeatable(SealForProfile.SealForProfilez.class)
public @interface SealForProfile {
+ /**
+ * Profile name to use while segregation the large interface. A sealed interface file will be generated following the naming convention:
+ * Sealed<ProfileName><LargeInterfaceSimpleName>
+ *
+ * @return a string containing the profile name
+ */
String value();
+ /**
+ * Internal annotation allowing @{@link SealForProfile} to be repeatable
+ */
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
- @interface SealForProfiless {
+ @interface SealForProfilez {
+ /**
+ * array attribute allowing @{@link SealForProfile} to be repeatable
+ *
+ * @return array of @SealForProfile instances
+ */
SealForProfile[] value();
}
}
\ No newline at end of file
diff --git a/src/main/java/org/jisel/SealForProfiles.java b/src/main/java/org/jisel/SealForProfiles.java
index 93294c9..7160cd0 100644
--- a/src/main/java/org/jisel/SealForProfiles.java
+++ b/src/main/java/org/jisel/SealForProfiles.java
@@ -1,12 +1,62 @@
+/**
+ * Copyright (c) 2022 Mohamed Ashraf Bayor
+ *
+ * For each one of the specified profiles names, a sealed interface will be generated following the naming convention: Sealed<ProfileName><LargeInterfaceSimpleName>
+ * <LargeInterfaceSimpleName> corresponds to the simplename of the interface being segregated.
+ * See @{@link SealForProfiles} attributes documentation.
+ */
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.METHOD})
+@Repeatable(SealForProfiles.SealForProfilezz.class)
public @interface SealForProfiles {
+
+ /**
+ * Profile name to use while segregation the large interface. A sealed interface file will be generated following the naming convention:
+ * Sealed<ProfileName><LargeInterfaceSimpleName>
+ *
+ * @return an array of the profiles names
+ */
String[] value();
+
+ /**
+ * Internal annotation allowing @{@link SealForProfiles} to be repeatable
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @Target(ElementType.METHOD)
+ @interface SealForProfilezz {
+ /**
+ * array attribute allowing @{@link SealForProfiles} to be repeatable
+ *
+ * @return array of @SealForProfiles instances
+ */
+ SealForProfiles[] value();
+ }
}
\ No newline at end of file
diff --git a/src/main/java/org/jisel/generator/CodeGenerator.java b/src/main/java/org/jisel/generator/CodeGenerator.java
new file mode 100644
index 0000000..dee78ce
--- /dev/null
+++ b/src/main/java/org/jisel/generator/CodeGenerator.java
@@ -0,0 +1,239 @@
+/**
+ * Copyright (c) 2022 Mohamed Ashraf Bayor
+ *
+ * Practice proper to Jisel only to avoid compilation errors for sealed interfaces not having any existing subtypes
+ *
+ * @param permitsMap {@link Map} containing parents/subtypes information. The Map key is the profile name whose generated
+ * sealed interface will be a parent interface, while the value is the list of profiles names whose
+ * sealed interfaces will be generated as subtypes
+ * @param largeInterfaceElement {@link Element} instance of the large interface being segregated
+ */
+ default void addFinalClassToPermitsMap(final Map
+ * Same is also used to generate the list of concrete methods of the convenience final class generated for the bottom-level generated sealed interfaces
+ */
+sealed interface MethodsGenerator extends CodeGenerator, StringGenerator permits SealedInterfaceMethodsGenerator {
+
+ /**
+ * Generates a list of abstracts methods definitions and appends it to the sealed interface code being generated
+ *
+ * @param sealedInterfaceContent {@link StringBuilder} object containing the sealed interface code being generated
+ * @param methodsSet {@link Set} of {@link Element} instances representing each one of the abstract methods to generate
+ */
+ void generateAbstractMethodsFromElementsSet(StringBuilder sealedInterfaceContent, Set
+ * Generates a list of concrete methods definitions (signature and body), and appends it to the final class being generated
+ *
+ * @param sealedInterfaceContent {@link StringBuilder} object containing the sealed interface code being generated
+ * @param methodsSet {@link Set} of {@link Element} instances representing each one of the abstract methods to generate
+ */
+ void generateEmptyConcreteMethodsFromElementsSet(StringBuilder sealedInterfaceContent, Set
+ * A final class is always generated by Jisel for the bottom-level generated sealed interfaces.
+ * The generated final class implements the provided large interface and implements all its methods by providing default return values for each.
+ */
+public class FinalClassContentGenerator implements StringGenerator {
+
+ private final CodeGenerator javaxGeneratedGenerator;
+ private final ExtendsGenerator extendsGenerator;
+ private final MethodsGenerator methodsGenerator;
+
+ /**
+ * FinalClassContentGenerator constructor. Instantiates needed instances of {@link JavaxGeneratedGenerator}, {@link SealedInterfaceExtendsGenerator}
+ * and {@link SealedInterfaceMethodsGenerator}
+ */
+ public FinalClassContentGenerator() {
+ this.javaxGeneratedGenerator = new JavaxGeneratedGenerator();
+ this.extendsGenerator = new SealedInterfaceExtendsGenerator();
+ this.methodsGenerator = new SealedInterfaceMethodsGenerator();
+ }
+
+ /**
+ * Generates content of the final class generated for the provided large interface
+ *
+ * @param processingEnvironment {@link ProcessingEnvironment} object, needed to access low-level information regarding the used annotations
+ * @param largeInterfaceElement {@link Element} instance of the large interface being segregated
+ * @param sealedInterfacesPermitsMap {@link Map} containing information about the subtypes permitted by each one of the sealed interfaces to be generated
+ * @return the final class string content
+ */
+ public String generateFinalClassContent(
+ final ProcessingEnvironment processingEnvironment,
+ final Element largeInterfaceElement,
+ final Map
- * The generateRecord() method params map is not required
+ * Generates the {@link javax.annotation.processing.Generated} annotation section at the top of the generated interfaces or classes with the attributes: value, date and comments
*/
public final class JavaxGeneratedGenerator implements CodeGenerator {
@@ -46,10 +45,10 @@ private void buildGeneratedAnnotationSection(final StringBuilder recordClassCont
date = "%s",
comments = "version: %s"
)
- """
- , JiselAnnotationProcessor.class.getName()
- , ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
- , getAppVersion()
+ """,
+ JiselAnnotationProcessor.class.getName(),
+ ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME),
+ getAppVersion()
));
}
@@ -65,7 +64,7 @@ private String getAppVersion() {
}
@Override
- public void generateCode(final StringBuilder recordClassContent, final Map
+ * Sample report:
+ * com.bayor.jisel.annotation.client.hierarchicalinheritance.Sociable
+ * Created sealed interfaces:
+ * SealedActiveWorkerSociable
+ * - Children:
+ * _SociableFinalCass
+ * SealedWorkerSociable
+ * - Children:
+ * SealedActiveWorkerSociable
+ * com.bayor.jisel.annotation.client.hierarchicalinheritance.subclasses.StudentWorkerHybrid
+ * SealedStudentSociable
+ * - Children:
+ * com.bayor.jisel.annotation.client.hierarchicalinheritance.subclasses.StudentWorkerHybrid
+ * SealedSociable
+ * - Children:
+ * SealedWorkerSociable
+ * SealedStudentSociable
+ */
+public class ReportGenerator implements StringGenerator {
+
+ /**
+ * Generates a Report file listing all generated sealed interfaces for the provided large interfaces.
+ *
+ * @param largeInterfaceElement {@link Element} instance of the large interface being segregated
+ * @param sealedInterfacesToGenerateMap {@link Map} containing information about the sealed interfaces to be generated
+ * @param sealedInterfacesPermitsMap {@link Map} containing information about the subtypes permitted by each one of the sealed interfaces to be generated
+ * @return a string containing the text report
+ */
+ public String generateReportForBloatedInterface(final Element largeInterfaceElement,
+ final Map
+ * The sealed interface generation process also includes the final class and report generation
+ */
+public class SealedInterfaceSourceFileGenerator implements StringGenerator {
+
+ private final SealedInterfaceContentGenerator sealedInterfaceContentGenerator;
+ private final FinalClassContentGenerator finalClassContentGenerator;
+ private final ReportGenerator reportGenerator;
+
+ /**
+ * SealedInterfaceSourceFileGenerator constructor. Creates needed instances of {@link SealedInterfaceContentGenerator},
+ * {@link FinalClassContentGenerator} and {@link ReportGenerator}
+ */
+ public SealedInterfaceSourceFileGenerator() {
+ this.sealedInterfaceContentGenerator = new SealedInterfaceContentGenerator();
+ this.finalClassContentGenerator = new FinalClassContentGenerator();
+ this.reportGenerator = new ReportGenerator();
+ }
+
+ /**
+ * @param processingEnvironment {@link ProcessingEnvironment} object, needed to access low-level information regarding the used annotations
+ * @param sealedInterfacesToGenerateByLargeInterface {@link Map} containing information about the sealed interfaces to be generated.
+ * To be populated and/or modified if needed. The key represents the {@link Element} instance of
+ * each one of the large interfaces to be segregated, while the associated value is
+ * a Map of profile name as the key and a Set of Element instances as the value.
+ * The Element instances represent each one of the abstract methods to be
+ * added to the generated sealed interface corresponding to a profile.
+ * @param sealedInterfacesPermitsByLargeInterface Map containing information about the subtypes permitted by each one of the sealed interfaces to be generated.
+ * To be populated and/or modified if needed. The key represents the Element instance of
+ * each one of the large interfaces to be segregated, while the associated value is
+ * a Map of profile name as the key and a List of profiles names as the value.
+ * @return List of all created source files
+ * @throws IOException if an I/O error occured
+ */
+ public List
+ * Sample value to be parsed by the regex: @org.jisel.AddToProfile(profile="ActiveWorker", largeInterface="com.bayor.jisel.annotation.client.data.Sociable")
+ */
+ String ADD_TO_PROFILE_REGEX = "AddToProfile\\((.*?)\\)";
+ /**
+ * Regex expression to read attributes information provided using the {@link org.jisel.AddToProfiles} annotation.
+ * Sample value to be parsed by the regex: @org.jisel.AddToProfiles(profiles={"Student", "Worker"}, largeInterface="com.bayor.jisel.annotation.client.data.Sociable")
+ */
+ String ADD_TO_PROFILES_REGEX = "AddToProfiles\\((.*?)\\)";
+
+ /**
+ * Title of the text report displayed in the logs during compilation.
+ * The report is displayed only when an unexpected scenario was encountered (ex: More than 1 top-level parent interfaces found, profile not existing,...)
+ */
+ String STATUS_REPORT_TITLE = "JISEL GENERATION REPORT";
+
+ /**
+ * Displayed only when a "severe" error occurred while a sealed interface file was being generated
+ */
+ String FILE_GENERATION_ERROR = "Error generating sealed interfaces";
+ /**
+ * Displayed as a header while listing the successfully generated files
+ */
+ String FILE_GENERATION_SUCCESS = "Successfully generated";
+
+ /**
+ * Fully qualified name of the {@link org.jisel.SealForProfile} annotation
+ */
+ String ORG_JISEL_SEAL_FOR_PROFILE = "org.jisel.SealForProfile";
+ /**
+ * Fully qualified name of the {@link org.jisel.SealForProfiles} annotation
+ */
+ String ORG_JISEL_SEAL_FOR_PROFILES = "org.jisel.SealForProfiles";
+ /**
+ * Fully qualified name of the {@link org.jisel.SealForProfile.SealForProfilez} annotation
+ */
+ String ORG_JISEL_SEAL_FOR_PROFILEZ = "org.jisel.SealForProfile.SealForProfilez";
+ /**
+ * Fully qualified name of the {@link org.jisel.SealForProfiles.SealForProfilezz} annotation
+ */
+ String ORG_JISEL_SEAL_FOR_PROFILEZZ = "org.jisel.SealForProfiles.SealForProfilezz";
+ /**
+ * Fully qualified name of the {@link org.jisel.AddToProfile} annotation
+ */
+ String ORG_JISEL_ADD_TO_PROFILE = "org.jisel.AddToProfile";
+ /**
+ * Fully qualified name of the {@link org.jisel.AddToProfiles} annotation
+ */
+ String ORG_JISEL_ADD_TO_PROFILES = "org.jisel.AddToProfiles";
+ /**
+ * Fully qualified name of the {@link org.jisel.AddToProfile.AddToProfilez} annotation
+ */
+ String ORG_JISEL_ADD_TO_PROFILEZ = "org.jisel.AddToProfile.AddToProfilez";
+ /**
+ * Fully qualified name of the {@link org.jisel.AddToProfiles.AddToProfilezz} annotation
+ */
+ String ORG_JISEL_ADD_TO_PROFILEZZ = "org.jisel.AddToProfiles.AddToProfilezz";
+
+ /**
+ * Default value to use for boolean returned values
+ */
+ String DEFAULT_BOOLEAN_VALUE = "false";
+ /**
+ * Default value to use for numeric returned values (int, long, float, double,...)
+ */
+ String DEFAULT_NUMBER_VALUE = "0";
+ /**
+ * Default value to use for Object returned values
+ */
+ String DEFAULT_NULL_VALUE = "null";
+
+ /**
+ * Array of methods to exclude while pulling the list of all inherited methods of a class or interface
+ */
+ String[] METHODS_TO_EXCLUDE = {"getClass", "wait", "notifyAll", "hashCode", "equals", "notify", "toString"};
+
+ /**
+ * Message displayed during compilation when 1 or many provided profiles are not found in the provided parent interfaces.
+ */
+ String ADD_TO_PROFILE_REPORT_MSG = "1 or many provided profiles are not found in the provided parent interfaces. Check your profiles and/or parent interfaces names.";
+ /**
+ * Message displayed during compilation when more than 1 top-level parent sealed interfaces was encountered based on provided profiles
+ */
+ String SEAL_FOR_PROFILE_REPORT_MSG = "More than 1 Top-Level Parent Sealed Interfaces will be generated. Check your profiles mapping.";
+
+ /**
+ * "Report.txt"
+ */
+ String JISEL_REPORT_SUFFIX = "Report.txt";
+
+ /**
+ * Header displayed above the list of the generated sealed interfaces, in the Jisel Report file
+ */
+ String JISEL_REPORT_CREATED_SEALED_INTERFACES_HEADER = "Created sealed interfaces:";
+
+ /**
+ * Header displayed above the list of the sub-types of the generated sealed interfaces, in the Jisel Report file
+ */
+ String JISEL_REPORT_CHILDREN_HEADER = "Children:";
+
+ /**
+ * Removes all commas from the provided string
+ *
+ * @param text contains commas as a string separator
+ * @return provided text with all commas removed
+ */
+ static String removeCommaSeparator(final String text) {
+ return asList(text.split(COMMA_SEPARATOR)).stream().collect(joining());
+ }
+
+ /**
+ * Constructs a string based on the provided profile and a large interface {@link Element} instance, according to the naming convention:
+ * Sealed<ProfileName><LargeInterfaceSimpleName>
+ *
+ * @param profile name of the profile
+ * @param interfaceElement {@link Element} instance of the large interface to be segregated
+ * @return a string following Jisel sealed interface naming convention
+ */
+ default String sealedInterfaceNameConvention(final String profile, final Element interfaceElement) {
+ var nameSuffix = removeCommaSeparator(profile).equals(interfaceElement.getSimpleName().toString()) ? EMPTY_STRING : interfaceElement.getSimpleName().toString();
+ // any profile name starting w _ (final classes names) or containing a dot (classes annotated with addtoprofile) is returned as is
+ return removeCommaSeparator(profile).startsWith(UNDERSCORE) || profile.contains(DOT) ? removeCommaSeparator(profile) : format(
+ "%s%s%s",
+ SEALED_PREFIX,
+ removeCommaSeparator(profile),
+ nameSuffix
+ );
+ }
+
+ /**
+ * Constructs a string based on the provided profiles and a large interface {@link Element} instance, according to the naming convention:
+ * Sealed<ProfileName><LargeInterfaceSimpleName>
+ *
+ * @param profiles {@link List} of profiles names
+ * @param interfaceElement {@link Element} instance of the large interface to be segregated
+ * @return a List of string literals following Jisel sealed interface naming convention
+ */
+ default List
+ * The informational message provided is a String literal describing the absence of an unique parent sealed interface,
+ * for each one of the provided large interfaces to be segregated
+ */
+ Map
+ * If an unique parent sealed interface is detected, the Map value is an Optional containing a comma-separated concatenation of all profiles sharing same common methods
+ */
+ default Map