Skip to content

Commit

Permalink
JIS-01: completed 1.0 - ready to merge
Browse files Browse the repository at this point in the history
  • Loading branch information
mohamed-ashraf-bayor committed Dec 28, 2021
1 parent e14a9e0 commit 8b6fe6f
Show file tree
Hide file tree
Showing 16 changed files with 188 additions and 104 deletions.
102 changes: 82 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
## JISEL: Java Interface Segregation Library
Interface Segregation Library for Java 17
# JISEL: Java Interface Segregation Library
Minimum Java 17 Required

Pitch Video:
...
Pitch Video: https://youtu.be/nkbu6zxV3R0

### How to Install ?
## Installation

If you are running a Maven project, add the latest release dependency to your pom.xml
```xml
Expand All @@ -14,35 +13,98 @@ If you are running a Maven project, add the latest release dependency to your po
<version>1.0</version>
</dependency>
```
You will also need to include the same dependency as an additional annotation processor in the Maven Compiler plugin of your project
```xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<release>17</release>
<compilerArgs>-Xlint:unchecked</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>org.jisel</groupId>
<artifactId>jisel</artifactId>
<version>1.0</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
```

For other build tools, please check: [Maven Central](https://search.maven.org/artifact/org.jisel/jisel/1.0/jar).

### Use on your declared bloated interfaces methods
## Provided Annotations

### @SealForProfile / @SealForProfiles
To be used only on abstract methods of the large interfaces you need to segregate
```java
import SealForProfile;
public interface Sociable {

String STUDENT = "Student";
String WORKER = "Worker";
String ACTIVE_WORKER = "ActiveWorker";

@SealForProfiles({STUDENT, WORKER, ACTIVE_WORKER})
String startConversation();

@SealForProfile(STUDENT)
boolean attendClass(String fieldOfStudy);

@SealForProfile(STUDENT)
void askForHelpWhenNeeded();

@SealForProfile(WORKER)
@SealForProfile(ACTIVE_WORKER)
// both annotations above can be replaced with: @SealForProfiles({WORKER, ACTIVE_WORKER})
boolean[] joinOfficeSocialGroups(String[] groups, int maximum);

public interface InterfaceA {
@SealForProfile
void something();
@SealForProfile(ACTIVE_WORKER)
void leadOfficeSocialGroup(String groupName);

@SealForProfile(ACTIVE_WORKER)
double createNewOfficeSocialGroup(String groupName, List<String> starters);
}
```

### Use on your declared child classes implementing generated sealed interfaces

### @AddToProfile / @AddToProfiles
To be used only on classes (or interfaces) implementing (or extending) any of the sealed interfaces generated by the use of @SealForProfile(s)
```java
import AddToProfile;
@AddToProfiles(profiles = {STUDENT, WORKER}, largeInterface = "com.bayor.jisel.annotation.client.hierarchicalinheritance.Sociable")
// the above line can be replaced with the following 2:
// @AddToProfile(profile = STUDENT, largeInterface = "com.bayor.jisel.annotation.client.hierarchicalinheritance.Sociable")
// @AddToProfile(profile = WORKER, largeInterface = "com.bayor.jisel.annotation.client.hierarchicalinheritance.Sociable")
public final class StudentWorkerHybrid implements SealedStudentSociable, SealedWorkerSociable {
@Override
public String startConversation() throws IllegalStateException {
return null;
}

@Override
public void askForHelpWhenNeeded() {

}

@AddToProfile("PROFILE_NAME")
public final class ClientA implements SealedInterfaceA {
// ...
@Override
public boolean attendClass(String param0) throws IllegalArgumentException {
return false;
}

@Override
public boolean[] joinOfficeSocialGroups(String[] param0, int param1) {
return new boolean[0];
}
}

```

### Sample classes for testing
### Sample interfaces and classes for testing
[https://github.com/mohamed-ashraf-bayor/jisel-annotation-client](https://github.com/mohamed-ashraf-bayor/jisel-annotation-client)

### Invalid Uses of Jisel
The annotation should be used ONLY on interfaces created in your own project.

### Issues, Bugs, Suggestions
Contribute to the project's growth by reporting issues or making improvement suggestions [here](https://github.com/mohamed-ashraf-bayor/jisel/issues/new/choose)
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
<packaging>jar</packaging>

<name>Jisel</name>
<description>Interface Segregation Library for Java 17</description>
<url>http://jisel.org</url>
<description>Java Interface Segregation Library</description>
<url>https://jisel.org/</url>

<licenses>
<license>
Expand All @@ -21,7 +21,7 @@
</licenses>

<scm>
<connection>scm:git:git://github.com/mohamed-ashraf-bayor/froporec.git</connection>
<connection>scm:git:git://github.com/mohamed-ashraf-bayor/jisel.git</connection>
<developerConnection>scm:git:git@github.com:mohamed-ashraf-bayor/mohamed-ashraf-bayor.git</developerConnection>
<url>https://github.com/mohamed-ashraf-bayor/jisel</url>
<tag>HEAD</tag>
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/jisel/AddToProfile.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
/**
* 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.<br><br>
* All sealed interfaces generated by Jisel follow the naming convention: <b>Sealed&#60;ProfileName&#62;&#60;LargeInterfaceSimpleName&#62;</b><br>
* See &#64;AddToProfile attributes documentation.<br><br>
* See &#64;{@link AddToProfile} attributes documentation.<br><br>
*/
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE})
Expand Down Expand Up @@ -65,7 +65,7 @@
@Target(ElementType.TYPE)
@interface AddToProfilez {
/**
* array attribute allowing &#64;AddToProfile to be repeatable
* array attribute allowing &#64;{@link AddToProfile} to be repeatable
*
* @return array of &#64;AddToProfile instances
*/
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/org/jisel/AddToProfiles.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@
/**
* 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.<br><br>
* All sealed interfaces generated by Jisel follow the naming convention: <b>Sealed&#60;ProfileName&#62;&#60;LargeInterfaceSimpleName&#62;</b><br>
* See &#64;AddToProfile attributes documentation.<br><br>
* See &#64;{@link AddToProfiles} attributes documentation.<br><br>
*/
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE})
@Repeatable(AddToProfiles.AddToProfilezz.class)
public @interface AddToProfiles {

/**
* <i>Not Required</i> - specifies an array containing the names of any of the profiles used with the &#64;SealForProfile annotations in the large interface definition.
* <i>Not Required</i> - specifies an array containing the names of any of the profiles used with the &#64;{@link SealForProfile} annotations in the large interface definition.
* Each one of the profiles names corresponds to the <b>&#60;ProfileName&#62;</b> from the sealed interfaces naming convention.<br>
* If not provided or empty, the annotated class, interface or record will be added to the permits list of the generated parent sealed interface.<br>
* Also, each one of the provided profiles names MUST be one of the profiles defined in the large interface definition using &#64;SealForProfile. If not,
Expand All @@ -59,13 +59,13 @@
String largeInterface();

/**
* Internal annotation allowing &#64;AddToProfiles to be repeatable
* Internal annotation allowing &#64;{@link AddToProfiles} to be repeatable
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
@interface AddToProfilezz {
/**
* array attribute allowing &#64;AddToProfiles to be repeatable
* array attribute allowing &#64;{@link AddToProfiles} to be repeatable
*
* @return array of &#64;AddToProfiles instances
*/
Expand Down
5 changes: 2 additions & 3 deletions src/main/java/org/jisel/JiselAnnotationProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
import static org.jisel.generator.StringGenerator.ORG_JISEL_SEAL_FOR_PROFILEZZ;

/**
* Jisel annotation processor class. Picks up and processes all elements annotated with @SealForProfile, @SealForProfiles, @AddToProfile and @AddToProfiles<br>
* Jisel annotation processor class. Picks up and processes all elements annotated with @{@link SealForProfile}, @{@link SealForProfiles}, @{@link AddToProfile} and @{@link AddToProfiles}<br>
*/
@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})
Expand All @@ -76,8 +76,7 @@ public class JiselAnnotationProcessor extends AbstractProcessor implements Strin
private final SealedInterfaceSourceFileGenerator sealedInterfaceSourceFileGenerator;

/**
* Constructor of JiselAnnotationProcessor.
* Initializes unique instances of SealForProfileHandler, AddToProfileHandler and SealedInterfaceSourceFileGenerator to be used within the class
* JiselAnnotationProcessor constructor. Initializes needed instances of {@link SealForProfileHandler}, {@link AddToProfileHandler} and {@link SealedInterfaceSourceFileGenerator}
*/
public JiselAnnotationProcessor() {
this.sealForProfileHandler = new SealForProfileHandler();
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/jisel/SealForProfile.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
* For the specified profile name, a sealed interface will be generated following the naming convention:
* <b>Sealed&#60;ProfileName&#62;&#60;LargeInterfaceSimpleName&#62;</b><br><br>
* <b>&#60;LargeInterfaceSimpleName&#62;</b> corresponds to the simplename of the interface being segregated.<br><br>
* See &#64;SealForProfile attributes documentation.<br><br>
* See &#64;{@link SealForProfile} attributes documentation.<br><br>
*/
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.METHOD})
Expand All @@ -48,13 +48,13 @@
String value();

/**
* Internal annotation allowing &#64;SealForProfile to be repeatable
* Internal annotation allowing &#64;{@link SealForProfile} to be repeatable
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
@interface SealForProfilez {
/**
* array attribute allowing &#64;SealForProfile to be repeatable
* array attribute allowing &#64;{@link SealForProfile} to be repeatable
*
* @return array of &#64;SealForProfile instances
*/
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/jisel/SealForProfiles.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
* Annotation to be applied only on top of abstract methods of an interface you intend to segregate.<br><br>
* For each one of the specified profiles names, a sealed interface will be generated following the naming convention: <b>Sealed&#60;ProfileName&#62;&#60;LargeInterfaceSimpleName&#62;</b><br><br>
* <b>&#60;LargeInterfaceSimpleName&#62;</b> corresponds to the simplename of the interface being segregated.<br><br>
* See &#64;SealForProfiles attributes documentation.<br><br>
* See &#64;{@link SealForProfiles} attributes documentation.<br><br>
*/
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.METHOD})
Expand All @@ -47,13 +47,13 @@
String[] value();

/**
* Internal annotation allowing &#64;SealForProfiles to be repeatable
* Internal annotation allowing &#64;{@link SealForProfiles} to be repeatable
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
@interface SealForProfilezz {
/**
* array attribute allowing &#64;SealForProfiles to be repeatable
* array attribute allowing &#64;{@link SealForProfiles} to be repeatable
*
* @return array of &#64;SealForProfiles instances
*/
Expand Down
34 changes: 17 additions & 17 deletions src/main/java/org/jisel/generator/CodeGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,16 @@ sealed interface ExtendsGenerator extends CodeGenerator, StringGenerator permits

/**
* Generates the "extends" clause of a sealed interface being generated, along with the list of parent interfaces, based on
* a provided Map containing parents/subtypes information (the permits Map) and the name of the profile for which the
* a provided {@link Map} containing parents/subtypes information (the permits Map) and the name of the profile for which the
* sealed interface will be generated
*
* @param processingEnvironment {@link ProcessingEnvironment} object, needed to access low-level information regarding the used annotations
* @param sealedInterfaceContent StringBuilder object containing the sealed interface code being generated
* @param permitsMap Map containing parents/subtypes information. The Map key is the profile name whose generated
* @param sealedInterfaceContent {@link StringBuilder} object containing the sealed interface code being generated
* @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 processedProfile name of the profile whose sealed interface is being generated
* @param largeInterfaceElement Element instance of the large interface being segregated
* @param largeInterfaceElement {@link Element} instance of the large interface being segregated
*/
void generateExtendsClauseFromPermitsMapAndProcessedProfile(
ProcessingEnvironment processingEnvironment,
Expand Down Expand Up @@ -96,15 +96,15 @@ sealed interface PermitsGenerator extends CodeGenerator, StringGenerator permits

/**
* Generates the "permits" clause of a sealed interface being generated, along with the list of parent interfaces, based on
* a provided Map containing parents/subtypes information (the permits Map) and the name of the profile for which the
* a provided {@link Map} containing parents/subtypes information (the permits Map) and the name of the profile for which the
* sealed interface will be generated
*
* @param sealedInterfaceContent StringBuilder object containing the sealed interface code being generated
* @param permitsMap Map containing parents/subtypes information. The Map key is the profile name whose generated
* @param sealedInterfaceContent {@link StringBuilder} object containing the sealed interface code being generated
* @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 processedProfile name of the profile whose sealed interface is being generated
* @param largeInterfaceElement Element instance of the large interface being segregated
* @param largeInterfaceElement {@link Element} instance of the large interface being segregated
*/
void generatePermitsClauseFromPermitsMapAndProcessedProfile(
StringBuilder sealedInterfaceContent,
Expand All @@ -123,14 +123,14 @@ default void generateCode(final StringBuilder classOrInterfaceContent, final Lis
}

/**
* Adds a generated final class to the Map containing parents/subtypes information, only for the sealed interfaces at the
* lowest-level of the generated hierarchy (also know as childless interfaces).<br>
* Adds a generated final class to the {@link Map} containing parents/subtypes information, only for the sealed interfaces at the
* lowest-level of the generated hierarchy (also known as childless interfaces).<br>
* Practice proper to Jisel only to avoid compilation errors for sealed interfaces not having any existing subtypes
*
* @param permitsMap Map containing parents/subtypes information. The Map key is the profile name whose generated
* @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 Element instance of the large interface being segregated
* @param largeInterfaceElement {@link Element} instance of the large interface being segregated
*/
default void addFinalClassToPermitsMap(final Map<String, List<String>> permitsMap, final Element largeInterfaceElement) {
var finalClassName = UNDERSCORE + largeInterfaceElement.getSimpleName().toString() + FINAL_CLASS_SUFFIX;
Expand All @@ -154,17 +154,17 @@ sealed interface MethodsGenerator extends CodeGenerator, StringGenerator permits
/**
* Generates a list of abstracts methods definitions and appends it to the sealed interface code being generated
*
* @param sealedInterfaceContent StringBuilder object containing the sealed interface code being generated
* @param methodsSet Set of {@link Element} instances representing each one of the abstract methods to generate
* @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<Element> methodsSet);

/**
* Mainly used for a final class generation.<br>
* Generates a list of concrete methods definitions (signature and body), and appends it to the final class being generated
*
* @param sealedInterfaceContent StringBuilder object containing the sealed interface code being generated
* @param methodsSet Set of {@link Element} instances representing each one of the abstract methods to generate
* @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<Element> methodsSet);

Expand All @@ -177,7 +177,7 @@ default void generateCode(final StringBuilder classOrInterfaceContent, final Lis
* Checks whether the provided method {@link Element} instance has any arguments
*
* @param methodElement method {@link Element} instance
* @return true if the provided method has any arguments
* @return true if the provided method has any arguments, false otherwise
*/
default boolean methodHasArguments(final Element methodElement) {
return methodElement.toString().indexOf(CLOSING_PARENTHESIS) - methodElement.toString().indexOf(OPENING_PARENTHESIS) > 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public FinalClassContentGenerator() {
*
* @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 Map containing information about the subtypes permitted by each one of 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 the final class string content
*/
public String generateFinalClassContent(
Expand Down
Loading

0 comments on commit 8b6fe6f

Please sign in to comment.