25 Mart 2021 Perşembe

MapStruct @Mapping Anotasyonu - Alanların Üstüne Yazılır

Giriş
@Mapping Anotasyonu şu işler için kullanıır
- Eğer alanlar arasında isim uyumsuzluğu varsa, mapping'i kodla belirtmek gerekir
- Eğer "custom mapping method" kullanmak istiyorsak

dateFormat Alanı
Örnek
Şöyle yaparız
@Mapper
public interface CustomerMapper {
  @Mapping(source="orderDate", target="stringDate", dateFormat= "dd.MM.yyy")
  Customer orderToCustomer(Order order);
}
defaultValue Alanı
Örnek
Şöyle yaparız
@Mapper
public interface CustomerMapper {
  @Mapping(source="age", target="cust.age", defaultValue= "NA")
  @Mapping(source="categoryId", constant="101")
  CustomerDto customerToCustomerDto(Customer customer);
}
expression Alanı
Açıklaması şöyle
expression(“java(…)”) : java code should be used to map on specific attribute.
Açıklaması şöyle
In case your expression has reference to some other classes, then you need to specify all such classes in the imports method of @Mapper annotation like —
@Mapper(imports = UUID.class)
or
@Mapper(imports = {UUID.class, Date.class})
Örnek
Şöyle yaparız
@Mapper(imports= UUID.class)
public interface CustomerMapper {
  @Mapping(target="id", expression="java(UUID.randomUUID().toString() )")
  CustomerDto customerToCustomerDto(Customer customer);
}
ignore Alanı
Açıklaması şöyle
ignore=true : Ignore mapping on specific attribute.
Örnek
Şöyle yaparız
@Mapping(source="id", target="id", ignore = true)
public User toEntity(UserModel userModel);
qualifiedByName Alanı
Açıklaması şöyle
There can be cases where you have to perform some complicated steps to map two fields. In such cases we can use the qualifiedByName method of @Mapping annotation to specify the method which should be invoked to perform that mapping.

- If using Java 8 and later versions, they can be defined as default or static methods within the same interface.
- If using a Java version older than Java 8, you can define all the mappings in an Abstract class instead of the Interface.

The method that contains logic must be annotated with the annotation @Named and it must contain the same name as the string you provided to the qualifiedByName method.
Örnek
Şöyle yaparız
@Mapper
public interface CustomerMapper {
  @Mapping(source"="amountInDollars", target="amountInCents",
qualifiedByName="dollarsToCents")
  CustomerDto customerToCustomerDto(Customer customer);

  @Named("dollarsToCents")
  default String dollarsToCents(Float dollars) {
    return String.valueOf(dollars * 100);
  }
}
source + target Alanları
Açıklaması şöyle
source : A source attribute should be mapped from.
target : A target attribute should be mapped to.
Örnek - source + target
Şöyle yaparız
@Mapper
public interface CarMapper {
  CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );

  @Mapping(source = "make", target = "yearOfMake")
  CarDTO carToCarDto(Car car);
}
Örnek
@Mapping anotasyonu birden fazla kez kullanılabilir. Ayrıca source nesnenin alanlarına da erişilebilir. Şöyle yaparız. Burada Doctor sınıfında Speciality tipinden ve ismi speciality olan bir sınıf var. Bu sınıfın da name isimli bir alanı var
@Mapping(source = "phone", target = "contact")
@Mapping(source = "speciality.name", target = "specialityName")
DoctorDto toDto(Doctor doctor);
source + target + qualifiedByName Alanları - Custom Mapping Method
Eğer source alandan target alana dönüşüm için kendi metodumuzu belirtmek istersek kullanırız

Örnek - Alan Değerine Göre
Şöyle yaparız.  Burada source olarak üye alan ismi kullanılıyor.
@Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR)
public interface FooMapper {

  @Mapping(source = "field1", target = "field2", qualifiedByName = "myConverter")
  Bar toFoo (Foo foo);

  @Named("myConverter")
  default int myConverter(int value) { return value * 2;}
}
Örnek - Nesneye Göre
Şöyle yaparız. Burada source olarak üye alan ismi değil, metod parametresi olan foo yazılıyor.
@Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR)
public interface FooMapper {

  @Mapping(source = "foo", target = "field2", qualifiedByName = "myConverter")
  Bar toFoo (Foo foo);

  @Named("myConverter")
  default int myConverter(Foo foo) { return value * 2;}
}


24 Mart 2021 Çarşamba

MapStruct @ObjectFactory Anotasyonu

Giriş
Örnek
Elimizde şöyle bir kod olsun
public class FooDto {
  char reference;
}

public class Foo {
  MyEnum reference;
  public Foo (String str) {...}
}

public enum MyEnum {
  A('a'), B('b');

  private final char value;

  private MyEnum(char ch) { this.value = ch;}

  public toChar () { return value;}

  public static MyEnum valueOf (char ch) {
    for (MyEnum e : values()) {
      if (e.toChar () == ch) {
        return e;
      }
    }
  }
}
Şöyle yaparız. Burada Foo nesnemiz için @ObjectFactory ile bir factory metodu tanımlıyoruz. Ayrıca Dto'dan gelen char tipini MyEnum tipine eşlemek için createMyEnum metodunu kodluyoruz
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ObjectFactory;
import org.mapstruct.ReportingPolicy;
@Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR) public interface FooMapper { Foo toFoo(FooDto dto); @ObjectFactory default Foo createFoo() { new Foo ("test"); } default MyEnum createMyEnum(char c){ return MyEnum.valueOf(c); } }


23 Mart 2021 Salı

System Sınıfı genv() vs getProperty

Giriş
getenv() işletim sistemi tarafından sağlanan ortam değişkenlerini (environment variables) döndürür. 
- getProperty() JVM'i çalışırken belirtilen değişkenleri döndürür.


getenv metodu
Ortam değişkenine erişim sağlar. Döndürülen map değiştirilemez. Açıklaması şöyle
Returns an unmodifiable string map view of the current system environment.
Şöyle yaparız.
 Map<String, String> env = System.getenv();
Şöyle yaparız.
System str = System.getenv("...");
getProperty metodu
Açıklaması şöyle
java.lang.System.getProperty()’ API underlyingly uses ‘java.util.Hashtable.get()’ API. Please be advised that ‘java.util.Hashtable.get()’ is a synchronized API. It means only one thread can invoke the ‘java.util.Hashtable.get()’ method at any given time. If a new thread tries to invoke ‘java.util.Hashtable.get()’ API when the first thread is still executing it, the new thread will be put in a BLOCKED state. When a thread is in the BLOCKED state, it won’t be able to progress forward. Only when the first thread completes executing the ‘java.util.Hashtable.get()’ API, new thread will be able to progress forward. Thus if ‘java.lang.System.getProperty()’ or ‘java.util.Hashtable.get()’ is invoked in critical code paths, it will impact the response time of the transaction.
Bu metod sadece String döner. Eğer bir property değerini Integer olarak okumak istersek Integer.getInteger() kullanılır

Örnek
Elimizde şöyle bir JVM parametresi olsun
“-DappName=buggyApp”
Şöyle yaparız
System str = System.getProperty("appName");
java.ext
extension dizinleri şöyle alınır.
System str = System.getProperty("java.ext.dirs");
Çıktı olarak şunu alırız.
D:\glassfish4\jdk7\jre\lib\ext;C:\windows\Sun\Java\lib\ext
java.home
Şöyle yaparız. D:\jdk1.8.0\jre gibi bir çıktı verir.
System str = System.getProperty("java.home");
java.version
Java sürümü şöyle alınır.
System str = System.getProperty("java.version")
1.8.0_91 gibi bir sonuç alırız.

os.name
Şöyle yaparız
public final class OsHelper {

  public static final String OS = System.getProperty("os.name").toLowerCase();

  public static boolean isLinux() {
    return OS.contains("nux");
  }

  public static boolean isUnixFamily() {
    return (OS.contains("nix") || OS.contains("nux") || OS.contains("aix"));
  }
  
  public static boolean isMac() {
    return (OS.contains("mac") || OS.contains("darwin"));
  }
  
  public static boolean isWindows() {
    return OS.contains("windows");
  }
}
sun
Sistemin 32 veya 64 bit olduğunu anlamak için şöyle yaparız.
System.getProperty("sun.arch.data.model")
user.home
Kullanıcının home dizini şöyle alınır. Linux'ta /home/myuser/Downloads gibi bir şey verir.
File downloads = new File(System.getProperty("user.home"), "Downloads");
Daha kötü bir yöntemle şöyle yaparız.
File directory = new File(System.getProperty("user.dir") 
         + System.getProperty("file.separator")+ "Images";
user.name
Kullanıcının adı şöyle alınır.
String userName = System.getProperty("user.name"); //platform independent

22 Mart 2021 Pazartesi

Collectors.joining metodu

Giriş
Bu metodun 3 tane overload edilmiş hali var. Aslında StringJoiner ile aynı işi yapar. İmzası şöyle
Collector<CharSequence, ?, String> joining()
Collector<CharSequence, ?, String> joining(CharSequence delimiter) {
Collector<CharSequence, ?, String> joining(CharSequence delimiter,
                                           CharSequence prefix,
                                           CharSequence suffix) {
joining metodu
Ayraç (delimiter) olmadan iki tane string nesnesini birleştirir
Örnek
Şöyle yaparız
var strs = List.of("one", "two", "three");

String s1 = strs.stream().collect(Collectors.joining());
// onetwothree

String s2 = strs.stream().collect(Collectors.joining("\t"));
// one two three

String s3 = strs.stream().collect(Collectors.joining(",", "{", "}"));
// {one,two,three}
joining metodu - delimiter
Örnek
Şöyle yaparız.
var strings = stream.collect(Collectors.joining(", "));

joining 
metodu - delimeter + prefix + suffix
İmzası şöyle
Collectors.joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)
Örnek
Şöyle yaparız
String s = Arrays.asList(123, 456, 789)
    .stream()
    .map(Object::toString)
    .collect(Collectors.joining("), (", "(", ")"));
// (123), (456), (789)
Örnek
Şöyle yaparız.
String s = stringList.stream().collect(Collectors.joining(" and ", "prefix_", "_suffix"))
Örnek
Şöyle yaparız.
String values = list.stream().collect(Collectors.joining("','", "'", "'"));
Çıktı olarak şunu alırız.
'rest','test','best'

21 Mart 2021 Pazar

Collections.rotate metodu

Örnek - collection + distance Sola Kaydırma
Şöyle yaparız
List<DayOfWeek> list = new ArrayList<>(List.of(DayOfWeek.MONDAY, DayOfWeek.TUESDAY,
DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY, DayOfWeek.SUNDAY)); Collections.rotate(list, list.size() - list.indexOf(DayOfWeek.WEDNESDAY));
System.out.println(list);
Çıktı olarak şunu alırız
[WEDNESDAY, THURSDAY, FRIDAY, SUNDAY, MONDAY, TUESDAY]


Hazelcast NetworkConfig Sınıfı

Giriş
Bu sınıf Config nesnesine atanır.

getJoin metodu
Örnek
Şöyle yaparız
Config config = new Config().setClusterName("Sample Hz Cluster");
NetworkConfig network = config.getNetworkConfig();
network.setPortAutoIncrement(true);

JoinConfig join = network.getJoin();
join.getMulticastConfig().setEnabled(true);
join.getTcpConfig().setEnabled(true)
  .addMember("192.168.0.107");
setJoin metodu - JoinConfig 
join configuration tanımı yapılabilir

Örnek
Şöyle yaparız
NetworkConfig networkConfig = new NetworkConfig()
  .setPort(5900)  
  .setPortAutoIncrement(false);

JoinConfig joinConfig = new JoinConfig();
TcpIpConfig tcpIpConfig = new TcpIpConfig();
tcpIpConfig.setConnectionTimeoutSeconds(30); 
tcpIpConfig.setEnabled(true);
    
List<String> memberList = new ArrayList<>();
memberList.add("machine1");
tcpIpConfig.setMembers(memberList);

joinConfig.setTcpIpConfig(tcpIpConfig);

networkConfig.setJoin(joinConfig);

Config config = new Config();
config.setNetworkConfig(networkConfig);

19 Mart 2021 Cuma

RxJava Backpressure - Geri tepme

Giriş
Açıklaması şöyle. Yani hızlı bir Producer ve yavaş bir Consumer varsa, Producer bu durum karşısında ezilmez.
... considering a fast data producer and a slow data consumer, backpressure is the mechanism that 'pushes back' on the producer not to be overwhelmed by data.
Şeklen şöyle

Açıklaması şöyle. Producer'ın ezilmemesinin sebebi, tüketen tarafın Subscription.request() metodu ile veriyi çekmesi.
A Subscriber MUST signal demand via Subscription.request(long n) to receive onNext signals.

The intent of this rule is to establish that it is the responsibility of the Subscriber to decide when and how many elements it is able and willing to receive. To avoid signal reordering caused by reentrant Subscription methods, it is strongly RECOMMENDED for synchronous Subscriber implementations to invoke Subscription methods at the very end of any signal processing. It is RECOMMENDED that Subscribers request the upper limit of what they are able to process, as requesting only one element at a time results in an inherently inefficient "stop-and-wait" protocol.

-- Reactive Streams specifications for the JVM
Açıklaması şöyle
To cope with that, RxJava offers two main strategies to handle 'overproduced' items:
1. Store items in a buffer
2. Drop items

RxJava 3 Sınıfları
Sınıflar şöyle

Flowable
Açıklaması şöyle
A flow of 0..N items. It supports Reactive-Streams and backpressure.
Observable
Açıklaması şöyle
A flow of 0..N items. It doesn't support backpressure.
Single
Açıklaması şöyle
A flow of exactly: 1 item, or an error.
Maybe
Açıklaması şöyle
A flow with either: no items, exactly one item, or an error.
Completable
Açıklaması şöyle
A flow with no item but either: a completion, or an error signal.