<?xml version="1.0" encoding="UTF-8"?>
<!--

    Copyright (C) 2015 The Gravitee team (http://gravitee.io)

    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.

-->
<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>
        <groupId>io.gravitee.am</groupId>
        <artifactId>gravitee-am-parent</artifactId>
        <version>4.12.0-alpha.4</version>
    </parent>

    <artifactId>gravitee-am-management-api-sdk-java</artifactId>
    <name>Gravitee IO - Access Management - Management API Java SDK</name>
    <description>Java client SDK generated from the Access Management Management API OpenAPI specification.</description>

    <properties>
        <!--
            Pin bytecode target to JDK 21 so consumers on the mainline gravitee
            toolchain (e.g. gravitee-alpha-module-aim) can compile against this
            SDK. AM server modules stay on JDK 25; only this thin generated
            client downgrades. JDK 25 JVMs load class files compiled against
            release 21 without issue.
        -->
        <maven.compiler.release>21</maven.compiler.release>
        <openapi-generator.version>7.22.0</openapi-generator.version>
        <jackson.version>2.18.2</jackson.version>
        <jackson-databind-nullable.version>0.2.6</jackson-databind-nullable.version>
        <jakarta.annotation-api.version>2.1.1</jakarta.annotation-api.version>
        <sdk.package.base>io.gravitee.am.sdk.management</sdk.package.base>
    </properties>

    <dependencies>
        <!-- vertx generator runtime deps -->
        <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-core</artifactId>
        </dependency>
        <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-web-client</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <dependency>
            <groupId>io.swagger.core.v3</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>2.2.25</version>
        </dependency>
        <dependency>
            <groupId>jakarta.annotation</groupId>
            <artifactId>jakarta.annotation-api</artifactId>
            <version>${jakarta.annotation-api.version}</version>
        </dependency>
        <!-- Required by useBeanValidation: generated models reference jakarta.validation.constraints.* -->
        <dependency>
            <groupId>jakarta.validation</groupId>
            <artifactId>jakarta.validation-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-params</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!--
                Pre-generation spec transform. The upstream OpenAPI spec is produced by the
                Management API's swagger scan and has two quirks that Java's strictly-typed
                client generators reject (TypeScript tolerates them at runtime):

                  * The `NewProtectedResourceFeature` / `UpdateProtectedResourceFeature`
                    parents declare the discriminator `type` as an unconstrained `string`,
                    while their subclasses (`NewMcpTool`, `UpdateMcpTool`) redeclare `type`
                    with an enum — producing parent-`String` vs subclass-`Enum` field and
                    getter collisions in Java.

                  * The sibling `ProtectedResourceFeature` parent already expresses `type`
                    as an enum; subclasses correctly inherit. We reshape the two stale
                    parents to match that working pattern.

                We copy the spec into target/ and rewrite it locally — the upstream Java
                code and the committed spec are left untouched.
            -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <executions>
                    <execution>
                        <id>prepare-openapi-spec</id>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <phase>initialize</phase>
                        <configuration>
                            <target>
                                <mkdir dir="${project.build.directory}"/>
                                <copy file="${project.basedir}/../docs/mapi/openapi.yaml"
                                      tofile="${project.build.directory}/openapi-patched.yaml"
                                      overwrite="true"/>

                                <!-- Promote `type` to an enum on the two stale parent schemas.
                                     Matches only where `type: string` immediately precedes
                                     `discriminator:` with no existing `enum:` block. -->
                                <replaceregexp file="${project.build.directory}/openapi-patched.yaml"
                                               match="(\n        type:\n          type: string\n)(      discriminator:)"
                                               replace="\1          enum:${line.separator}          - MCP_TOOL${line.separator}\2"
                                               flags="g"
                                               byline="false"/>

                                <!-- Remove the redundant `type` redeclaration from subclass
                                     allOf overrides (anchored by the 10-space indent unique
                                     to that context, with the scopes sibling as tail anchor). -->
                                <replaceregexp file="${project.build.directory}/openapi-patched.yaml"
                                               match="\n          type:\n            type: string\n            enum:\n            - MCP_TOOL\n(          scopes:)"
                                               replace="${line.separator}\1"
                                               flags="g"
                                               byline="false"/>

                                <!-- Strip `requiredPermissions` from Patch* schemas. The Java
                                     models expose getRequiredPermissions() as a derived getter
                                     used internally by REST resources for permission checks
                                     (see PermissionSettingUtils). The OpenAPI scan picks it up
                                     as a settable schema property, so the SDK ships it as a
                                     field that gets serialized as `"requiredPermissions": []`
                                     on every PATCH — and AM's own deserializer rejects it as
                                     unrecognized (400). The property is meaningless on the
                                     wire either way; remove it from the spec before generation
                                     so the SDK never emits it. -->
                                <replaceregexp file="${project.build.directory}/openapi-patched.yaml"
                                               match="        requiredPermissions:\n          uniqueItems: true\n          type: array\n          items:\n            type: string\n            enum:\n(            - [A-Z0-9_]+\n)+"
                                               replace=""
                                               flags="g"
                                               byline="false"/>
                            </target>
                        </configuration>
                    </execution>

                    <!--
                        Post-generation fix. Even with the spec reshaped, openapi-generator
                        hard-codes `this.type = getClass().getSimpleName()` into the
                        discriminator subclass constructors. Parent `type` is now a typed
                        enum, so the String assignment won't compile. Jackson populates
                        `type` from the JSON payload during deserialization, so the
                        assignment is redundant — strip it.
                    -->
                    <execution>
                        <id>patch-discriminator-subclass-constructors</id>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <phase>process-sources</phase>
                        <configuration>
                            <target>
                                <replaceregexp match="\s*this\.type = this\.getClass\(\)\.getSimpleName\(\);\s*\n"
                                               replace="${line.separator}"
                                               flags="g"
                                               byline="false">
                                    <fileset dir="${project.build.directory}/generated-sources/openapi/src/main/java/io/gravitee/am/sdk/management/model">
                                        <include name="McpTool.java"/>
                                        <include name="NewMcpTool.java"/>
                                        <include name="UpdateMcpTool.java"/>
                                    </fileset>
                                </replaceregexp>
                            </target>
                        </configuration>
                    </execution>

                    <!--
                        supportVertxFuture: the vertx-generator default-method template passes
                        a Promise where a Handler<AsyncResult<T>> is expected. In Vert.x 4 these
                        were interchangeable; in Vert.x 5 Promise no longer implements Handler.
                        Rewrite the call site to pass `promise::handle`.
                    -->
                    <execution>
                        <id>fix-vertx5-future-default-methods</id>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <phase>process-sources</phase>
                        <configuration>
                            <target>
                                <replaceregexp match="([ (])promise\);"
                                               replace="\1promise::handle);"
                                               flags="g"
                                               byline="true">
                                    <fileset dir="${project.build.directory}/generated-sources/openapi/src/main/java/io/gravitee/am/sdk/management/api">
                                        <include name="*.java"/>
                                    </fileset>
                                </replaceregexp>
                            </target>
                        </configuration>
                    </execution>

                    <!--
                        useBeanValidation: the vertx api template emits @Valid on collection
                        element types but doesn't import jakarta.validation.Valid. Inject the
                        import into api/*.java files that reference it.
                    -->
                    <execution>
                        <id>add-valid-import-to-api</id>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <phase>process-sources</phase>
                        <configuration>
                            <target>
                                <replaceregexp match="(import io\.vertx\.core\.json\.JsonObject;\n)"
                                               replace="\1import jakarta.validation.Valid;${line.separator}"
                                               flags="g"
                                               byline="false">
                                    <fileset dir="${project.build.directory}/generated-sources/openapi/src/main/java/io/gravitee/am/sdk/management/api">
                                        <include name="*.java"/>
                                        <containsregexp expression="@Valid"/>
                                    </fileset>
                                </replaceregexp>
                            </target>
                        </configuration>
                    </execution>

                    <!--
                        Vert.x 5 dropped vertx-rx-java (RxJava 1 EOL). The vertx generator
                        still emits an api/rxjava/* wrapper layer compiled against rx.Single.
                        Delete it so only the standard WebClient-based api/* survives.
                    -->
                    <execution>
                        <id>strip-rxjava1-wrappers</id>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <phase>process-sources</phase>
                        <configuration>
                            <target>
                                <delete dir="${project.build.directory}/generated-sources/openapi/src/main/java/io/gravitee/am/sdk/management/api/rxjava"/>
                            </target>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.openapitools</groupId>
                <artifactId>openapi-generator-maven-plugin</artifactId>
                <version>${openapi-generator.version}</version>
                <executions>
                    <execution>
                        <id>generate-management-api-sdk</id>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <phase>generate-sources</phase>
                        <configuration>
                            <generatorName>java</generatorName>
                            <inputSpec>${project.build.directory}/openapi-patched.yaml</inputSpec>
                            <output>${project.build.directory}/generated-sources/openapi</output>
                            <apiPackage>${sdk.package.base}.api</apiPackage>
                            <modelPackage>${sdk.package.base}.model</modelPackage>
                            <invokerPackage>${sdk.package.base}.invoker</invokerPackage>
                            <generateApiTests>false</generateApiTests>
                            <generateModelTests>false</generateModelTests>
                            <generateApiDocumentation>false</generateApiDocumentation>
                            <generateModelDocumentation>false</generateModelDocumentation>
                            <skipValidateSpec>true</skipValidateSpec>
                            <configOptions>
                                <library>vertx</library>
                                <useVertx5>true</useVertx5>
                                <dateLibrary>java8</dateLibrary>
                                <openApiNullable>false</openApiNullable>
                                <hideGenerationTimestamp>true</hideGenerationTimestamp>
                                <useJakartaEe>true</useJakartaEe>
                                <!--
                                    Emit Future<T> operationId(...) defaults on every API
                                    interface alongside the Handler<AsyncResult<T>> form, so
                                    consumers can avoid Promise/Handler boilerplate at call sites.
                                -->
                                <supportVertxFuture>true</supportVertxFuture>
                                <!--
                                    Bean Validation annotations (@NotNull, @Size, @Pattern) on
                                    generated models so consumers can fail fast on bad payloads.
                                    performBeanValidation stays off — annotations only, no
                                    runtime validation cost.
                                -->
                                <useBeanValidation>true</useBeanValidation>
                                <performBeanValidation>false</performBeanValidation>
                                <!--
                                    Forward-compat: when AM adds a new enum constant, generated
                                    SDK fromValue() returns UNKNOWN_DEFAULT_OPEN_API instead of
                                    throwing — so older clients can still decode newer payloads.
                                -->
                                <enumUnknownDefaultCase>true</enumUnknownDefaultCase>
                                <!--
                                    AM's Patch* models read collection fields with tri-state
                                    semantics: absent = preserve, [] = clear. The generator
                                    default-initialises every container field to an empty
                                    collection, so plain Jackson serialisation (USE_DEFAULTS)
                                    emits `"grantTypes": []` etc. on every PATCH and AM clears
                                    untouched fields. Initialise containers to null so the
                                    consumer's NON_NULL inclusion drops them from the wire,
                                    while explicit `setX(List.of())` still serialises `[]`
                                    (preserving "clear by empty list" intent).
                                -->
                                <containerDefaultToNull>true</containerDefaultToNull>
                                <!--
                                    The Management API serializes all enums as lowercase
                                    (see ObjectMapperResolver in gravitee-am-management-api-rest),
                                    while generated enum constants stay uppercase. Switch
                                    fromValue() to equalsIgnoreCase so deserialization succeeds
                                    against wire payloads like "type":"agent".
                                -->
                                <useEnumCaseInsensitive>true</useEnumCaseInsensitive>
                            </configOptions>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <version>3.6.1</version>
                <executions>
                    <execution>
                        <id>add-generated-sources</id>
                        <goals>
                            <goal>add-source</goal>
                        </goals>
                        <phase>generate-sources</phase>
                        <configuration>
                            <sources>
                                <source>${project.build.directory}/generated-sources/openapi/src/main/java</source>
                            </sources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <!-- Generated sources are build output; skip license header check. -->
            <plugin>
                <groupId>com.mycila</groupId>
                <artifactId>license-maven-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
