2 Ocak 2024 Salı

SpringDoc OpenAPI JSON Çıktısı

Giriş
JSON çıktıyı görmek için şu adrese gideriz 
http://localhost:8080/v3/api-docs
Çıktı şöyle
{
  "openapi": "3.0.1",
  "info": {
    "title": "...",
    "description": "...",
    "version": "v1"
  },
  "servers": [
    {
      "url": "http://localhost:8080",
      "description": "Generated server url"
    }
  ],
  "paths": {
    "/rest/api/v1/cluster": {
      "get": {
        "tags": [
          "Cluster Controller"
        ],
        "summary": "Retrieve cluster status",
        "description": "Endpoint to retrieve the cluster status.",
        "operationId": "getClusterStatus",
        "responses": {
          ...
          }
        }
      }
    }
  "components": {
    "schemas": {
      "ClusterStatusModel": {
        ...
  }
}


25 Aralık 2023 Pazartesi

SpringDoc OpenAPI YAML Çıktısı

Giriş
OpenAPI çıktıyı yaml olarak görmek için şu adrese gideriz 
http://localhost:8080/v3/api-docs.yaml
Çıktı Bileşenleri
1. Metadata Sections
2. Servers and Tags Sections
3. Components Section
4. Path Section

1. Metadata Sections
Açıklaması şöyle
1. openapi — The openapi section indicates the version of OAS used. For example, “3.0.3” signifies major version 3 with patch version 3.
2. info — The info section contains metadata about the API, such as its title, description, terms of service, contact details, license information, and version.
3. externalDocs — The externalDocs section provides a link to extended documentation related to the API, including a description and URL.
Örnek
openapi: 3.0.3

info:
  title: Sample Ecommerce App API
  description: |
    This is a sample ecommerce app API
  termsOfService: https://github.com/someUserId/someProject/blob/main/LICENSE
  contact:
    name: Ecommerce Support
    url: https://www.ecomm.com
    email: support@ecomm.com
  license:
    name: MIT
    url: https://github.com/someUserId/someProject/blob/main/LICENSE
  version: 1.0.0

externalDocs:
  description: Any document link you want to generate along with API.
  url: http://swagger.io
2. Servers and Tags Sections
Açıklaması şöyle
4. servers — The servers section lists the servers hosting the API, facilitating interactive documentation through tools like Swagger UI.
5. tags — The tags section groups operations related to specific resources, allowing for better organization and grouping in generated code.
Örnek
servers:
  - url: https://ecommerce.swagger.io/v2

tags:
  - name: cart
    description: Everything about cart
    externalDocs:
      description: Find out more (extra document link)
      url: http://swagger.io
  - name: order
    description: Operation about orders
3. Components Section
Açıklaması şöyle
The components section is used to define models and reusable components, such as request bodies, responses, and schemas. 
Örnek
components:
  schemas:
    Cart:
      description: Shopping Cart of the user
      type: object
      properties:
        customerId:
          description: Id of the customer who possesses the cart
          type: string
        items:
          description: Collection of items in cart.
          type: array
          items:
            $ref: '#/components/schemas/Item'
4. Path Section
Açıklaması şöyle
The paths section defines API endpoints, including the URI, HTTP methods, parameters, responses, and more.
Örnek
paths:
  /api/v1/carts/{customerId}:
    get:
      tags:
        - cart
      summary: Returns the shopping cart
      description: Returns the shopping cart of a given customer
      operationId: getCartByCustomerId
      parameters:
        - name: customerId
          in: path
          description: Customer Identifier
          required: true
          schema:
            type: string
      responses:
        200:
          description: Successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Cart'
        404:
          description: Given customer ID doesn't exist
          content: {}


13 Aralık 2023 Çarşamba

spring-boot-maven-plugin repackage Goal - Fat Jar Oluşturur

Giriş
Spring boot uygulamasını paketlemek için gerekir.  Açıklaması şöyle.
Unfortunately, if we are working with a jar package, the basic Maven package goal doesn't include any of the external dependencies.

This means that we can use it only as a library in a bigger project.

To circumvent this limitation, we need to leverage the Maven Spring Boot plugin repackage goal to run our jar/war as a stand-alone application.
Maven 3.2 gerektirir. Açıklaması şöyle.
The Spring Boot Maven Plugin provides Spring Boot support in Maven, allowing you to package executable jar or war archives and run an application “in-place”. To use it you must be using Maven 3.2 (or better).
Eğer repackage goal maven package lifecycle'a bağlı değilse çalıştırmak için şöyle yaparız. Difference Between spring-boot:repackage and Maven package yazısına bakılabilir.
mvn package spring-boot:repackage
Bağlıysa sadece şöyle yaparız
mvn package
Bağlamak için şöyle yaparız. Bu en kullanılabilecek en basit hali.
<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <version>2.4.1</version>
  <executions>
    <execution>
      <goals>
        <goal>repackage</goal>
      </goals>
    </execution>
  </executions>
</plugin>
1. repackage Goal - Fat Jar Yapısı
Eğer fat jar'ı açarsak BOOT-INF dizininde kendi kodlarımızı görebiliriz. org ile başlayan dizinde de spring kodları var. Şeklen şöyle
|__BOOT-INF
|  |__classes //1
|  |__ lib //2
|__META-INF
|  |__ MANIFEST.INF
|__org
   |__ springframework
        |__ loader //3
Açıklaması şöyle
1. Project compiled classes
2. JAR dependencies
3. Spring Boot class-loading classes
Manifest dosyasının için şöyledir
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.foo.executable.jar.ExecutableJarApplication
mainClass Tag
Örnek
Eğer kodumuzda birden fazla main metodu varsa başlangıç olanını belirtmek için kullanırız. configuration tag'i için açıklama şöyle.
Your existing archive will be enhanced by Spring Boot during the package phase. The main class that you want to launch can either be specified using a configuration option, or by adding a Main-Class attribute to the manifest in the usual way. If you don’t specify a main class the plugin will search for a class with a public static void main(String[] args) method.
Şöyle yaparız.
<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>repackage</goal>
      </goals>
      <configuration>
        <mainClass>gpdi.MyApp</mainClass>
      </configuration>
    </execution>
  </executions>
</plugin>
classifier Tag
Örnek

Şöyle yaparız.
<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <version>${spring.boot.version}</version>
  <executions>
    <execution>
      <goals>
        <goal>repackage</goal>
      </goals>
      <configuration>
        <classifier>exec</classifier>
      </configuration>
    </execution>
  </executions>
</plugin>

4 Aralık 2023 Pazartesi

SpringMVC SpringServletContainerInitializer

Giriş
Şu satırı dahil ederiz
import org.springframework.web.SpringServletContainerInitializer;
Açıklaması şöyle. Yani Tomcat ServletContainerInitializer arayüzünü gerçekleştiren sınıflar arıyor. Bu sınıflardan bir tanesi de SpringServletContainerInitializer
Tomcat is searching for ServletContainerInitializer class at all the jar files included in the project if available. This class has to be stored exactly inside javax.servlet.ServiceContainerInitializer file which is placed in META-INF/services directory in each jar file.
Kalıtım şöyle
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
Açıklaması şöyle. Yani  jakarta.servlet.annotation.HandlesTypes anotasyonu ile jakarta.servlet.ServletContainerInitializer gerçekleştirimi hangi arayüzler ile ilgilendiğini Tomcat'e bildirir
In the ServletContainerInitializer, there is an annotation assigned called @HandlesTypes. The implementer can assign any class for it and Tomcat searches all the classes that have been extended or implemented to the assigned class. 
Böylece WebApplicationInitializer başlatılır

30 Kasım 2023 Perşembe

SpringContext @AliasFor Anotasyonu

Giriş
Şu satırı dahil ederiz
import org.springframework.core.annotation.AliasFor;
Bir açıklama burada


28 Kasım 2023 Salı

SpringScheduling Shedlock KeepAliveLockProvider Sınıfı

Giriş
Şu satırı dahil ederiz
import net.javacrumbs.shedlock.support..KeepAliveLockProvider;
Açıklaması şöyle
KeepAliveLockProvider extends the lock in the middle of the lockAtMostFor interval. For example, if the lockAtMostFor is 10 minutes the lock is extended every 5 minutes for 10 minutes until the lock is released. Please note that the minimal lockAtMostFor time supported by this provider is 30s. The scheduler is used only for the lock extension, single thread should be enough.
Örnek
Şöyle yaparız
@Configuration
public class ShedlockConfiguration {

  @Bean
  public LockProvider lockProvider(DataSource dataSource) {
    return new KeepAliveLockProvider(
      getJdbcTemplateLockProvider(dataSource),
      Executors.newSingleThreadScheduledExecutor()
    );
  }

  private JdbcTemplateLockProvider getJdbcTemplateLockProvider(DataSource dataSource) {
    return new JdbcTemplateLockProvider(
      JdbcTemplateLockProvider.Configuration.builder()
        .withJdbcTemplate(new JdbcTemplate(dataSource))
        .withDbUpperCase(true)
        .usingDbTime()
        .build()
      );
  }
}




9 Kasım 2023 Perşembe

SpringData ElasticSearch ReactiveElasticsearchClient Arayüzü

Giriş
Şu satırı dahil ederiz 
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
Örnek
Şöyle yaparız
@Configuration
public class ReactiveRestClientConfig extends AbstractReactiveElasticsearchConfiguration {
  @Override
  public ReactiveElasticsearchClient reactiveElasticsearchClient() {
    ClientConfiguration clientConfiguration = ClientConfiguration.builder()
      .connectedTo("localhost:9200")
      .build();
    return ReactiveRestClients.create(clientConfiguration);
  }
}