26 Temmuz 2023 Çarşamba

ArchUnit Layered Architecture Enforcement Kullanımı

Giriş
Açıklaması şöyle
In layered architectures, we define different layers and how those interact with each other.
Örnek
Şöyle yaparız
@ArchTest
static final ArchRule persistence_should_not_access_services =
  noClasses()
  .that()
  .resideInAPackage("..persistence..")
  .should()
  .accessClassesThat()
  .resideInAPackage("..service..");

@ArchTest
static final ArchRule services_should_only_be_accessed_by_controllers_or_other_services =
  classes()
  .that()
  .resideInAPackage("..service..")
  .should()
  .onlyBeAccessed()
  .byAnyPackage("..controller..", "..service..");
Örnek
Şöyle yaparız
@ArchTest
static final ArchRule layer_dependencies_are_respected_with_exception =
  layeredArchitecture().consideringAllDependencies()
  .layer("Controllers").definedBy("com.tngtech.archunit.example.layers.controller..")
  .layer("Services").definedBy("com.tngtech.archunit.example.layers.service..")
  .layer("Persistence").definedBy("com.tngtech.archunit.example.layers.persistence..")
  
  .whereLayer("Controllers").mayNotBeAccessedByAnyLayer()
  .whereLayer("Services").mayOnlyBeAccessedByLayers("Controllers")
  .whereLayer("Persistence").mayOnlyBeAccessedByLayers("Services")
  .ignoreDependency(SomeMediator.class, ServiceViolatingLayerRules.class);
Örnek
Şöyle yaparız
@Test
public void testThatHexagonalLayerIsRespected() {
  JavaClasses classes = new ClassFileImporter()
    .importPackages("com.modern.app");

  layeredArchitecture()
    .consideringAllDependencies()
    .layer("application").definedBy("..application..")
    .layer("domain").definedBy("..domain..")
    .layer("infrastructure").definedBy("..infrastructure..")
    
    .whereLayer("domain").mayOnlyBeAccessedByLayers("application", "infrastructure")
    .whereLayer("application").mayOnlyBeAccessedByLayers("infrastructure")
    .whereLayer("infrastructure").mayNotBeAccessedByAnyLayer()
    .check(classes);
}

20 Temmuz 2023 Perşembe

jcmd komutu Thread.print seçeneği - Thread Dump Alır

Giriş
Açıklaması şöyle. Uzunca bir çıktı verebilir.
This command is to get the thread dump i.e. it will print the stack trace of all threads currently running.
Örnek
Şöyle yaparız
# old schoool
jstack <pid>

# more modern
jcmd <pid> Thread.print
jcmd <class-name> Thread.print

# If no JDK, SIGQUIT dumps threads to System.out, extract from there
#   (this will just send a signal to the app, not trigger a shutdown)
kill -QUIT <pid>

# For a Kubernetes pod the java pid is typically 1
kubectl exec <pod-name> -- jstack 1
Örnek
Şöyle yaparız
jcmd pid Thread.print

17 Temmuz 2023 Pazartesi

AWS SDK Kullanımı

1. Java SDK
Şu satırı dahil ederiz
<dependency>
  <groupId>com.amazonaws</groupId>
  <artifactId>aws-java-sdk</artifactId>
  <version>1.12.525</version>
</dependency>

2. Java SDK Bundled Dependency
3. taraf bağımlıklarının başka paketlere taşındığı bir fat jar. Bu jar bayağı büyük. Şu satırı dahil ederiz
<dependency>
  <groupId>com.amazonaws</groupId>
  <artifactId>aws-java-sdk-bundle</artifactId>
  <version>${aws.sdk.version}</version>
</dependency>
Bir örnek burada

3. BOM Kullanımı
Örnek
Şu satırı dahil ederiz.  Burada Parent BOM'dan gelen bağımlılıkar versiyon olmadan <dependency> olarak tanımlanıyor.
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>bom</artifactId>
      <version>2.16.1</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>dynamodb</artifactId>
  </dependency>
</dependencies>

Retrofit

Giriş
Altta OKHttp kullanır

Örnek
Elimizde şöyle bir arayüz olsun
interface JsonPlaceholderApi {
    @GET("todos/{id}")
    Call<Todo> getTodo(@Path("id") int id);
}

class Todo {
    int userId;
    int id;
    String title;
    boolean completed;

    // getters and setters
}
Şöyle yaparız
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;


Retrofit retrofit = new Retrofit.Builder()
  .baseUrl("https://jsonplaceholder.typicode.com/")
  .addConverterFactory(GsonConverterFactory.create())
  .build();

JsonPlaceholderApi jsonPlaceholderApi = retrofit.create(JsonPlaceholderApi.class);

Call<Todo> call = jsonPlaceholderApi.getTodo(1);
call.enqueue(new Callback<Todo>() {
  @Override
  public void onResponse(Call<Todo> call, Response<Todo> response) {
    if (!response.isSuccessful()) {
      System.out.println("Unexpected code " + response);
      return;
    }
Todo todo = response.body();
    System.out.println(todo);
  }
@Override
  public void onFailure(Call<Todo> call, Throwable t) {
    t.printStackTrace();
  }
});

13 Temmuz 2023 Perşembe

ASM Kullanımı - Insturmentation

Giriş
Açıklaması şöyle
ASM is a widely-used bytecode manipulation library. It provides a comprehensive API for analyzing and modifying bytecode. ASM operates at a low level, giving developers fine-grained control over bytecode manipulation.
Örnek
Şöyle yaparız
import org.objectweb.asm.*;

public class ASMExample {
  public static void main(String[] args) throws Exception {
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
    cw.visit(Opcodes.V11, Opcodes.ACC_PUBLIC, "com/example/Calculator", null, "java/lang/Object", null);
        
    MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "add", "(II)I", null, null);
    mv.visitCode();
    mv.visitVarInsn(Opcodes.ILOAD, 1);
    mv.visitVarInsn(Opcodes.ILOAD, 2);
    mv.visitInsn(Opcodes.IADD);
    mv.visitInsn(Opcodes.IRETURN);
    mv.visitMaxs(2, 3);
    mv.visitEnd();
        
    cw.visitEnd();
        
    byte[] bytecode = cw.toByteArray();
        
    // Use the generated bytecode...
  }
}



ClassFileTransformer Arayüzü - Instrumentation API

Giriş
Şu satırı dahil ederiz
import java.lang.instrumen.Instrumentation;
Açıklaması şöyle
The ClassFileTransformer interface is a critical component of the Instrumentation API. It provides a transform() method that is called when a class is being loaded by the JVM. The transform() method receives the original class bytecode and returns the modified bytecode.
Örnek
Şöyle yaparız
import java.lang.instrument.Instrumentation;

public class LoggingAgent {
  public static void premain(String agentArgs, Instrumentation inst) {
    inst.addTransformer(new LoggingTransformer());
  }
}

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

public class LoggingTransformer implements ClassFileTransformer {
  @Override
  public byte[] transform(
    ClassLoader loader, 
    String className, 
    Class<?> classBeingRedefined, 
    ProtectionDomain protectionDomain, 
    byte[] classfileBuffer) throws IllegalClassFormatException {
        
    // Check if the class should be instrumented for logging
    if (className.startsWith("com.example")) {
      System.out.println("Instrumenting class: " + className);
            
      // Inject logging code into the class bytecode
      // ...
    }
    return classfileBuffer;
  }
}
Örnek
Şöyle yaparız
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

public class MethodTransformer implements ClassFileTransformer {
  @Override
  public byte[] transform(
    ClassLoader loader, 
    String className, 
    Class<?> classBeingRedefined, 
    ProtectionDomain protectionDomain, 
    byte[] classfileBuffer) throws IllegalClassFormatException {
        
    if (className.equals("com.example.Calculator")) {
      System.out.println("Instrumenting class: " + className);
            
      // Modify the bytecode of the add() method
      return modifyAddMethod(classfileBuffer);
    }
        
    return classfileBuffer;
  }
    
  private byte[] modifyAddMethod(byte[] originalBytecode) {
    // ... Bytecode manipulation to modify the add() method ...
  }
}

3 Temmuz 2023 Pazartesi

SequencedSet Arayüzü - Java 21 İle Geliyor

Giriş
SequencedCollection ile aynıdır. İlave olarak reversed() metodu sağlar. Kod şöyle
interface SequencedSet<E> extends SequencedCollection<E>, Set<E> {
  SequencedSet<E> reversed();
}

SequencedMap Arayüzü - Java 21 İle Geliyor

Giriş
Arayüz şöyle. LinkedHashMap, SortedMap  artık SequencedMap arayüzünden kalıtıyor
interface SequencedMap<K,V> extends Map<K,V> {
// new methods SequencedMap<K,V> reversed(); SequencedSet<K> sequencedKeySet(); SequencedCollection<V> sequencedValues(); SequencedSet<Entry<K,V>> sequencedEntrySet(); V putFirst(K, V); V putLast(K, V); // methods promoted from NavigableMap Entry<K, V> firstEntry(); Entry<K, V> lastEntry(); Entry<K, V> pollFirstEntry(); Entry<K, V> pollLastEntry(); }

SequencedCollection Arayüzü - Java 21 İle Geliyor

Giriş
Arayüz şöyle. List , Deque arayüzleri artık SequencedCollection arayüzünden kalıtıyor
interface SequencedCollection<E> extends Collection<E> {
  // new method
  SequencedCollection<E> reversed();
  // methods promoted from Deque
  void addFirst(E);
  void addLast(E);
  E getFirst();
  E getLast();
  E removeFirst();
  E removeLast();
}
getFirst metodu
Eskiden şöyle yapmak gerekiyordu
// First Element 
list.get(0)
Artık şöyle yaparız
list.getFirst()
getLast metodu
Eskiden şöyle yapmak gerekiyordu
// Last Element 
list.get(list.size()-1)
Artık şöyle yaparız
list.getLast()
reversed metodu
Açıklaması şöyle. Yani SequencedMap, SequencedSet gibi arayüzler SequencedCollection değil kendi tiplerini dönüyorlar
Covariant Return Types is an important Java feature that I feel has gotten less coverage than the others listed above. The addition of Sequenced Collections in Java 21 brings some recent attention to this important feature that was added in Java 5. The SequencedCollection interface has a method named reversed that has covariant overrides with more specific return types in SequencedSet, Deque, List, etc.