31 Ocak 2023 Salı

Stream.peek metodu - Dikkatli Olmak Lazım

Tüm elemenlar için çağrılır.forEach() ile benzer ancak esas amacı debug içindir. Açıklaması şöyle.
This method exists mainly to support debugging, where you want to see the elements as they flow past a certain point in a pipeline
SonarLint açıklaması şöyle
According to its JavaDocs, the intermediate Stream operation java.util.Stream.peek() “exists mainly to support debugging” purposes.

A key difference with other intermediate Stream operations is that the Stream implementation is free to skip calls to peek() for optimization purpose. This can lead to peek() being unexpectedly called only for some or none of the elements in the Stream.

As a consequence, relying on peek() without careful consideration can lead to error-prone code.
This rule raises an issue for each use of peek() to be sure that it is challenged and validated by the team to be meant for production debugging/logging purposes.
Verilen örnek şöyle
// Noncompliant Code Example
Stream.of("one", "two", "three", "four")
         .filter(e -> e.length() > 3)
         .peek(e -> System.out.println("Filtered value: " + e));

// Compliant Solution
Stream.of("one", "two", "three", "four")
         .filter(e -> e.length() > 3)
         .foreach(e -> System.out.println("Filtered value: " + e));
Debug
Örnek
Şöyle yaparız.
"abcd".chars().peek(e->System.out.print(e + ":"))
Çıktı olarak şunu alırız.
a:b:c:d:
Örnek
Şöyle yaparız.
Stream.of("one", "two", "three", "four")
  .filter(e -> e.length() > 3)
  .peek(e -> System.out.println("Filtered value: " + e))
  .map(String::toUpperCase)
  .peek(e -> System.out.println("Mapped value: " + e))
  .collect(Collectors.toList());
Setter Çağırmak
Açıklaması şöyle. Yani debug amacı dışında kullanılması yasak değil, ama teşvik te edilmiyor. Dolayısıyla tüm sorumluluk kodlayan kişide.
We can see that non-debugging usages are neither forbidden nor discouraged.
Örnek
Elimizde şöyle bir kod olsun. Burada peek() çağrılıyor. 
// The problem is that this behavior is highly deceiving because certain 
// Stream implementations can optimize out peek() calls.

Stream.of(Date.from(Instant.EPOCH))
  .peek(d -> d.setTime(Long.MAX_VALUE))
  .forEach(System.out::println);

// Sun Aug 17 08:12:55 CET 292278994
Ancak çağrılmadığı durumlar da olabilir. Bazı örnekler şöyle
List.of(1, 2, 3)
  .stream()
  .peek(System.out::println)
  .count();
// The result is empty

Stream.iterate(0, i -> i + 1)
  .peek(System.out::println)
  .findFirst();
// The result is empty
Örnek
Şöyle yaparız.
List<Foo> newFoos = foos.stream()
            .filter(Foo::isBlue)
            .peek(foo -> foo.setTitle("Some value"))
            .collect(Collectors.toList());
Hesap Yapmak
Örnek

Kalan yüzdeyi yazdırmak için kullanılabilir. Şöyle yaparız.
Stream<MyData> myStream = readData();
final AtomicInteger loader = new AtomicInteger();
int fivePercent = elementsCount / 20;
MyResult result = myStream
  .map(row -> process(row))
  .peek(stat -> {
    if (loader.incrementAndGet() % fivePercent == 0) {
      System.out.println(loader.get() + " elements on " + elementsCount + " treated");
      System.out.println((5*(loader.get() / fivePercent)) + "%");
    }
  })
  .reduce(MyStat::aggregate);

30 Ocak 2023 Pazartesi

Class.getDeclaredMethod metodu

Giriş
- Access modifier tipine bakmaksızın nesnenin tanımladığı - kalıtımla gelen hariç - ismi belirtilen metodu döner. 
- Class.getDeclaredMethod bir metodunun istenilen şeyi bulabilmesi için metoda geçilen parametrelerin de yani doğru verilmesi gerekir.

Örnek - public method
Elimizde şöyle bir sınıf olsun. Erişmek istediğiniz metod public.
public class Foo {
  public void isFoo(Object obj) {
    ...
  }
}
Metodu bulmak için şöyle yaparız.
Class c = Foo.class;
Method m = c.getDeclaredMethod("isFoo", Object.class);
Metodumuz birden çok parametre alsaydı ikinci parametreyi bir dizi olarak geçebilirdik.
String methodName = ...;
Class[] types = ...;
Method method = c.getDeclaredMethod(methodName, types);
Örnek - protected method
Elimizde şöyle bir sınıf olsun. Bu sefer erişmek istediğimiz metod protected.
public class PrivateCar {

  private String color;

  protected void drive() {
    System.out.println("this is private car! the color is:" + color);
  }
}
Şöyle yaparız.
Class clazz = loader.loadClass("javaReflect.test.PrivateCar");
Method method = clazz.getDeclaredMethod("drive");
Örnek - Method İmzası
MyClass sınıfı içinde bir main metodu olsun. 
public static void main(String[] args) {...}
Onu bulmak için şöyle yaparız. Burada metod imzasında parametrenin String[] olduğunu belirmek gerekiyor.
Method mainMethod = MyClass.classgetDeclaredMethod("main", String[].class);
Diğer
Örnek

Elimizde Foo ata sınıfı olsun.
public class Foo {
  public void doit() {
    System.out.println("good");
  }
}
Bu sınıftan kalıtan Bar sınıfı olsun
public class Bar extends Foo {
  public void doit() {
    System.out.println("bad");
  }
}
Method nesnesine Foo.class olarak erişsek bile ve hatta çağırırken yine Foo sınıfına cast etsek bile Bar sınıfının doIt() metodu çağrılır. Çıktı olarak bad alırız.
Bar b = new Bar();
/* Using Foo.class */
Method m = Foo.class.getDeclaredMethod("doit", new Class[]{});

m.invoke((Foo)b, new Object[]{});


27 Ocak 2023 Cuma

Testcontainers JDBC URL Kullanımı

Giriş
Açıklaması şöyle
... after making a very simple modification to your system's JDBC URL string, Testcontainers will provide a disposable stand-in database that can be used without requiring modification to your application code.
..
As long as you have Testcontainers and the appropriate JDBC driver on your classpath, you can simply modify regular JDBC connection URLs to get a fresh containerized instance of the database each time your application starts up.
Yani iki tane dependency gerekir.
1. Test containers
2. Veri tabanı için driver

Açıklaması şöyle. Yani JDBC URL kullanımında URL jdbc:tc:... şeklinde olmalı
You should use either
- the JDBC URL with tc: prefix and ContainerDatabaseDriver or
- container instance with getJdbcUrl() and the original driver (or let the system detect the driver for you), not both.

Kullanıcı İsmi ve Şifre
TestContainers normalde kullanıcı ismi ve şifreye gerek duymaz. Yani sadece URL ila bağlanabiliriz.
String jdbcUrl = "jdbc:tc:sqlserver:latest:///mydbName";
try (Connection conn = DriverManager.getConnection(jdbcUrl)) {
  ...
}
Stack trace şöyle. JDBC DriverManager kodu gidip Testcontainers içindeki ContainerDatabaseDriver sınıfını tetikliyor
at org.testcontainers.containers.GenericContainer.doStart(GenericContainer.java:349)
at org.testcontainers.containers.GenericContainer.start(GenericContainer.java:322)
at org.testcontainers.jdbc.ContainerDatabaseDriver.connect(ContainerDatabaseDriver.java:124)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:270)
Eğer istenirse container şöyle öldürülebilir
ContainerDatabaseDriver.killContainer(jdbcUrl);
ContainerDatabaseDriver.killContainers();
PostgreSQL
Kullanıcı ismi test ve şifresi test olan bir veri tabanı yaratır
Örnek
Şöyle yaparız. Kullanıcı ismi user, şifresi password olan bir veri tabanı yaratır
spring.datasource.url=jdbc:tc:postgresql://localhost/testdb
spring.datasource.driverClassName=org.testcontainers.jdbc.ContainerDatabaseDriver
spring.datasource.username=user
spring.datasource.password=password
MySQL
Kullanıcı ismi root ve şifresi test olan bir veri tabanı yaratır
Örnek
Şöyle yaparız
jdbc:tc:mysql:8.0.29:///mydb?TC_DAEMON=true&sessionVariables=sql_mode=ANSI
Örnek
Şöyle yaparız
jdbc:tc:mysql:8.0.29:///mydb?user=root?password=test?TC_DAEMON=true&sessionVariables=sql_mode=ANSI
MS SQL
Testcontainers JDBC URL Kullanımı yazısına taşıdım

MariaDB
Örnek
Şöyle yaparız
<dependency>
  <groupId>org.testcontainers</groupId>
  <artifactId>mariadb</artifactId>
  <version>1.17.6</version>
<scope>test</scope> </dependency> <dependency> <groupId>org.mariadb.jdbc</groupId> <artifactId>mariadb-java-client</artifactId> <version>3.1.2</version> <scope>test</scope> </dependency>
Şöyle yaparız
String jdbcUrl = 
"jdbc:tc:mariadb:latest:///mydbName?TC_DAEMON=true&sessionVariables=sql_mode=ANSI";
try (Connection conn = DriverManager.getConnection(jdbcUrl)) {
  ...
}

26 Ocak 2023 Perşembe

Files.newInputStream metodu - NIO

Giriş
Eğer Path olarak bir dizin verirse java.nio.file.AccessDeniedException fırlatır. Kalıtım şöyle
Exception
  IOException
    FileSystemException
      AccessDeniedException

Örnek
Elimizde bir path olsun
Path path = Paths.get("path/to/my/file");
Şöyle yaparız.
try (InputStream in = Files.newInputStream(path)) {
    // work with "in"
}

23 Ocak 2023 Pazartesi

IntelliJ Idea Debug İpuçları - Memory View

Giriş
Memory View penceresini açmak gerekir. Şöyle yaparız

Breakpoint ile durduğumuzda sınıflar yüklü değildir. Load classes tıklanır

Diff Sütunu
İki Break Point veya Step over arasındaki nesne sayısı farkını gösterir. Şeklen şöyle

Eğer bir nesneye çift tıklarsak bu nesnenin kullanıldığı her yeri görebiliriz.

Track New Instances
Array olmayan nesneler için kullanılabilir. Şeklen şöyle. Nesne için etkinse gözlük benzeri bir simge gösterilir

Eğer Track New Instances etkin değilse sağ tıklama menüsü şeklen şöyle.

Eğer etkinse sağ tıklama menüsü şeklen şöyle.

Show New Instances menüsüne tıklarsak şeklen şöyle. Sağ tarafta nesneni yaratılmasına sebep olan stack var.






IntelliJ Idea Debug İpuçları - Thread View

Threads View
Threads View açılır

Customize Threads View
Sağ tıklanır. Şeklen şöyle

Pencere şöyle

Eğer show thread groups seçerse Thread'ler artık grup isimlerine göre listelenirler. Şeklen şöyle


Thread Durumları
Monitor ise thread bir senkronizasyon nesnesi üzerinde bekliyordur. Şeklen şöyle

Async Stack Trace
Şeklen şöyle. ExecutorService.submit() gibi çağrıların nereden yapıldığını gösterir.





18 Ocak 2023 Çarşamba

JDB SQLIntegrityConstraintViolationException

Giriş
Şu satırı dahil ederiz
import java.sql.SQLIntegrityConstraintViolationException;

Eğer batch işlem yapılıyorsa bu exception yerine BatchUpdateException fırlatılır