23 Aralık 2020 Çarşamba

Collectors.toUnmodifiableSet metodu

Örnek
Şöyle yaparız
List<String> strings = Arrays.asList("alpha","beta","gamma","alpha");
Set<String> readOnlySet = strings
       .stream()
       .sorted()
       .collect(Collectors.toUnmodifiableSet());
// output: ["alpha","beta","gamma"]

Collectors.toSet metodu

Örnek
Elimizde bir Map olsun
Map<Key, Value> map = ...;
Tüm value nesnelerini bir Set'e doldurmak istersek şöyle yaparız.
Set<Key> keys = map.entrySet().stream()
  .filter(entry -> entry.getValue() == value)
  .map(entry -> entry.getKey())
  .collect(Collectors.toSet());
Eğer TreeSet olarak almak istersek Collectors.toCollection(TreeSet::new) metodunu kullanmak lazım. Şöyle yaparız
TreeSet<String> myTreeSet = Stream.of(...).collect(Collectors.toCollection(TreeSet::new));

22 Aralık 2020 Salı

ModelMapper API

Giriş
ModelMapper'in rakibi MapStruct kütüphanesi. MapStruct için bir örnek burada
MapStruct kod üreterek çalışıyor, yani bir code generator, ModelMapper ise kod üretmeden çalışıyor.
 
ModelMapper Sınıfı
constructor
Şöyle yaparız
ModelMapper mapper = new ModelMapper()
map metodu
Şöyle yaparız
UserRequest userRequest = ...;
User user = modelMapper.map(userRequest, User.class);

15 Aralık 2020 Salı

JPA JPQL Join Çeşitleri

Giriş
- JOIN - INNER JOIN ile aynı. Kesişimi verir
- LEFT JOIN - LEFT OUTER JOIN ile aynı
- RIGHT JOIN
- CROSS JOIN
- FETCH - JPA'ya mahsus


1. JOIN
JPQL JOIN yazısına taşıdım. Sadece randevusu olan doktorları yükler. Eğer ilişki LAZY ise child nesnenin tamamını yüklemez.  N+1 Select Problemine sebep olur

2. LEFT JOIN
Randevusu olan veya olmayan tüm doktorları yükler.  Eğer ilişki LAZY ise child nesnenin tamamını yüklemez.  N+1 Select Problemine sebep olur

3. RIGHT JOIN
Örnek ver

4. CROSS JOIN
Bir örnek burada

5. FETCH
FETCH hem JOIN hem de LEFT JOIN ile birlikte kullanılabilir. 

Yani 
- JOIN FETCH veya
- LEFT JOIN FETCH 
şeklinde kullanabiliriz.

- Eğer ilişki LAZY ise child nesnenin tamamıyla yüklenmesini sağlar. Yani ilişkiyi EAGER haline getirir. İlişkinin EAGER hale gelmesi kendi içinde de "Cartesian Product Problem" ine sebep oluyor. Onu da aşağıda yazdım.

Yani ilişkinin şöyle olması gerekir. Burada LAZY sadece daha rahat anlaşılsın diye yazılı. Yoksa @OneToMany'nin varsayılan davranışı zaten böyle
@OneToMany(fetch = FetchType.LAZY)
private Set<Department> department;

5.1 JOIN FETCH - Inner Join Gibi
JOIN FETCH yazısına taşıdım

5.2 LEFT JOIN FETCH - Left Outer Join Gibi
LEFT JOIN FETCH yazısına taşıdım

JPA N+1 Select/Query Problem

Giriş 
Parent nesneler yükleniyor ve döngü ile dolaşılıyor. Her parent nesne için child nesneleri çekecek bir SQL çalıştırılır.

Örnek
Şu kodda N+1 problemi ortaya çıkar
@OneToMany(mappedBy = "doctor", fetch = FetchType.LAZY)
private Collection<Appointment> appointments;
Örnek
Şu kodda N+1 problemi ortaya çıkar
List<Doctor> doctors = entityManager.createQuery("select d from Doctor d",
Doctor.class)
.getResultList();
for (Doctor doctor : doctors) {
  Assert.assertTrue(doctor.getAppointments().size() > 0);
}
Örnek
Şu kodda N+1 problemi ortaya çıkar
List<String> postTitlesStreamRecords = postRepository.findAll()
    .stream()
    .filter(
        post -> post.getTags()
                    .stream()
                    .map(Tag::getName)
                    .anyMatch(matchingTags::contains)
    )
    .sorted(Comparator.comparing(Post::getId))
    .map(Post::getTitle)
    .collect(Collectors.toList())
Çözüm 1
EAGER FETCH yapmak

Çözüm 2
JPQL kullanıyorsak "JOINT FETCH" yapmak. Yani nesne ve ilişkilerini tek seferde yüklemek

JPA JPQL Join yazısına bakabilirsiniz.

Çözüm 3
SQL kullanıyorsak INNER JOIN kullanırız.Şöyle yaparız.
public List<String> findPostTitleByTags(List<String> tags) {
  return entityManager.createNativeQuery("""
    select p.title
      from post p
      where exists (
        select 1
          from post_tag pt
          join tag t on pt.tag_id = t.id and pt.post_id = p.id
          where t.name in (:tags)
      )
      order by p.id
    """)
  .setParameter("tags", tags)
  .getResultList();
}
Çözüm 4

Static Olmayan Inner/Nested Class

Giriş
- Inner sınıf'ın başına private gibi bir modifier konulabilir
- Inner sınıf içinde bulunduğu Outer sınıfın alanlarına erişebilir.

Inner Sınıfı Yaratmak
Örnek
Şöyle yaparız
class Outer {
  private class Inner {...}

  void foo() {
    Inner a = this.new Inner();
    Inner b = new Outer.Inner();
    Inner c = new Inner();       // Recommended way to write it
  }
}
Örnek
Inner sınıfı dışarıdan yaratmak için şöyle yaparız.
Inner inner = new Outer().new Inner();
Inner Sınıf Static Metoda Sahip Olabilir
Java 16'dan itibaren Inner sınıf artık static metoda sahip olabiliyor.
Örnek
Şöyle yaparız
public class OuterClass {

  class InnerClass {
    static void printMe() {
      System.out.println("Inside inner class");
    }
  }

  public static void main(String[] args) {
    InnerClass.printMe();
  }
}
Dışarıdaki Sınıfın Alanlarına Erişme
Inner sınıf içinde bulunduğu Outer sınıfın alanlarına erişebilir.

Örnek
Şöyle yaparız.
class Foo {
  int outer_x = 100;
  void test() {
    Inner inner = new Inner();
    inner.display();
  }
  // this is an inner class
  class Inner {
    void display() {
       System.out.println("Display: outer_x = " + outer_x);
    }
  }
}
Örnek
Inner sınıf içinde bulunduğu Outer sınıfın atrribute'larına erişebilir. Bu yüzden Iterator örüntüsü için kullanıma uygundur. Şöyle yaparız.
// Typical use of a nonstatic member class
public class MySet<E> extends AbstractSet<E> {
  ... // Bulk of the class omitted

  public Iterator<E> iterator() {
    return new MyIterator();
  }

  private class MyIterator implements Iterator<E> {
    ...
  }
}
Dış Sınıftan İç Sınıfa Erişme
Örnek
Dış sınıf generic ise şöyle yaparız
import java.util.Arrays;

public class X<T> {
  class Z {}

  void m() {
    for (Object o : Arrays.asList(1, 2, 3)) {
      if (o instanceof X.Z) {}    // Compiles now
      if (o instanceof X<?>.Z) {} // Also
    }
  }
}
Serialization
Açıklaması şöyle. Yani inner class static değilse serialization çok problemli olabiliyor
Serialization of inner classes (i.e., nested classes that are not static member classes), including local and anonymous classes, is strongly discouraged for several reasons. 
1. Because inner classes declared in non-static contexts contain implicit non-transient references to enclosing class instances, serializing such an inner class instance will result in serialization of its associated outer class instance as well. 
2. Synthetic fields generated by javac (or other JavaTM compilers) to implement inner classes are implementation dependent and may vary between compilers; differences in such fields can disrupt compatibility as well as result in conflicting default serialVersionUID values. 
3. The names assigned to local and anonymous inner classes are also implementation dependent and may differ between compilers. 
4. Since inner classes cannot declare static members other than compile-time constant fields, they cannot use the serialPersistentFields mechanism to designate serializable fields. 
5. Finally, because inner classes associated with outer instances do not have zero-argument constructors (constructors of such inner classes implicitly accept the enclosing instance as a prepended parameter), they cannot implement Externalizable. None of the issues listed above, however, apply to static member classes.


14 Aralık 2020 Pazartesi

Mockito Kullanımı

Giriş
Mockito kullanabilmek için API'yi bilmek gerekiyor. API'nin çoğu Mockito sınıfı etrafında tanımlı.

Maven
"mockito-all" eski bir dependency ve artık kullanılmamalı

Örnek - Anotasyon Olmadan
Şu satırı dahil ederiz. 
<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-core</artifactId>
  <version>3.8.0</version>
  <scope>test</scope>
</dependency>
Örnek - Anotasyon İle JUnit 5
JUnit 5 ile kullanmak için şöyle yaparız
<dependency>
  <groupId>org.junit.jupiter</groupId>
  <artifactId>junit-jupiter-api</artifactId>
  <version>5.7.1</version>
  <scope>test</scope>
</dependency>

<dependency>
 <groupId>org.junit.jupiter</groupId>
  <artifactId>junit-jupiter-engine</artifactId>
  <version>5.7.1</version>
  <scope>test</scope>
</dependency>

<dependency>
 <groupId>org.junit.platform</groupId>
  <artifactId>junit-platform-launcher</artifactId>
  <version>1.7.1</version>
  <scope>test</scope>
</dependency>

Mock object yaratma ve davranışı tanımlama işlemleri burada yapılır

Mockito'ya ait runner tarafından koşturulan testlerde kullanılır