13 Nisan 2021 Salı

Lombok @UtilityClass Anotasyonu

Giriş
Açıklaması şöyle
@UtilityClass annotation which creates a private constructor that throws an exception, makes the class final, and makes all methods static.
Örnek
Şöyle yaparız
@UtilityClass
// will be made final
public class UtilityClass {
  // will be made static
  private final int GRUBHUB = “ GRUBHUB”;

  // autogenerated by Lombok
  // private UtilityClass() {
  //   throw new java.lang.UnsupportedOperationException("... cannot be instantiated");
  //}

  // will be made static
  public void append(String input) {
    return input + GRUBHUB;
  }
}

Lombok @Value Anotasyonu - Record Gibidir

Giriş
Açıklaması şöyle
@Value is similar to @Data except, all fields are made private and final by default and setters are not generated. These qualities make @Value objects effectively immutable. As the fields are all final, there is not a no argument constructor. Instead Lombok uses @AllArgsConstructor to generate an all arguments constructor. This results in a fully-functioning, effectively-immutable object.
Açıklaması şöyle
 Short for final @ToString, @EqualsAndHashCode, @AllArgsConstructor,   @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE), @Getter.

9 Nisan 2021 Cuma

DelayQueue Sınıfı

Giriş
Şu satırı dahil ederiz
import java.util.concurrent.DelayQueue;
PECS kuralına göre bu sınıf bir producer olduğu için extends kullanıyor. Tanımı şöyle
public class DelayQueue<E ? extends Delayed> extends AbstractQueue<E>
implements BlockingQueue<E>
1. İçine Delayed arayüzünü gerçekleştiren nesneler alır. 
2. DelayQueue ayrıca ScheduledThreadPoolExecutor tarafından da kullanılıyor.

Bu sınıfı düzgünce kullanabilmek için Delayed arayüzünü doğru kullanmak gerekir. 


7 Nisan 2021 Çarşamba

Byte Buddy - Java Compiler Kullanmadan Java Kodu Üretir

Giriş
Açıklaması şöyle
Byte Buddy is a lightweight and user-friendly bytecode manipulation library. It simplifies bytecode generation and modification by providing a high-level API. Byte Buddy allows for the creation of new classes, modification of existing classes, and dynamic creation of methods and fields.

Maven
Şu satırı dahil ederiz
<properties>
  <byte-buddy.version>1.12.11</byte-buddy.version>
</properties>

<dependencies>
  <dependency>
    <groupId>net.bytebuddy</groupId>
    <artifactId>byte-buddy</artifactId>
    <version>${byte-buddy.version}</version>
  </dependency>

  <dependency>
    <groupId>net.bytebuddy</groupId>
    <artifactId>byte-buddy-agent</artifactId>
    <version>${byte-buddy.version}</version>
  </dependency>
</dependencies>
ByteBuddy Sınıfı

redefine metodu
Belirtilen sınıfı değiştirebilmek mümkün

Örnek
Şöyle yaparız. Bu örnekte privateMethod() exception fırlatıyor. Onu başka bir metod ile değiştiriyoruz.
public class MainService {
  public void publicMethod() {
    privateMethod();
  }

  private void privateMethod() {
    throw new IllegalStateException();
  }
}

public class StubService {
  public static void privateMethod() {
    // empty
  }
}

public class MainWithOverridedMethod {
  public static void main(String[] args) throws Throwable {
    ByteBuddyAgent.install();

    Class<? extends MainService> cls = new ByteBuddy()
	  .redefine(MainService.class)
	  .method(named("privateMethod"))
	  .intercept(MethodDelegation.to(StubService.class))
	  .make()
	  .load(StubService.class.getClassLoader(), fromInstalledAgent())
	  .getLoaded();
    MainService mainService = cls.newInstance();
    mainService.publicMethod();
  }
}
subclass metodu
Belirtilen sınıftan kalıtan yeni bir sınıf döner
Örnek
Şöyle yaparız. Bu örnekte Object nesnesinden kalıtılıyor ve toString() metodunu başka bir metod ile değiştiriyoruz.
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.FixedValue;

public class ByteBuddyExample {
  public static void main(String[] args) throws Exception {
    Class<?> dynamicType = new ByteBuddy()
      .subclass(Object.class)
      .method(ElementMatchers.named("toString"))
      .intercept(FixedValue.value("Hello Byte Buddy!"))
      .make()
      .load(ByteBuddyExample.class.getClassLoader())
      .getLoaded();
        
      Object instance = dynamicType.getDeclaredConstructor().newInstance();
      System.out.println(instance.toString());
  }
}
1. Traditional Advice Dispatching Approaches
Açıklaması şöyle
By default, the enter and exit advice is copied into the target methods, as if the original author of the class had added the agent’s code into the method.
Advice kopyalamanın bazı iyi ve kötü tarafları var. Açıklaması şöyle
The advantage is that the advice has access to any value or type that is normally reachable from the instrumented method. In the above example, this allows accessing javax.servlet.http.HttpServletRequest, even though the agent does not itself ship with that interface. As the agent’s code is run within the targeted method, it simply picks up the type definition that is already available to the method itself.

On the downside, the advice code is no longer executed in the context that it is defined within. As a result, you can, for example, not set a breakpoint in an advice method, because it is never actually called. Remember: the methods are merely used as a template.
Örnek - inlined advice
Şöyle yaparız
@Advice.OnMethodEnter
public static long enter() {
  return System.nanoTime();
}

@Advice.OnMethodExit
public static void exit(@Advice.Argument(0) HttpServletRequest request,
                        @Advice.Enter long startTime) {
  System.out.printf("Request to %s took %d ns%n",
    request.getRequestURI(),
    System.nanoTime() - startTime);
}
Advice gerçek metodun içine kopyalandığı için sanki şöyle kodlanmış gibi olur
protected void service(HttpServletRequest req, HttpServletResponse resp) {
  long startTime = System.nanoTime();
  // original method body
  System.out.printf("Request to %s took %d ns%n",
    request.getRequestURI(),
    System.nanoTime() - startTime);
}
Örnek - inlined advice
Byte Buddy AgentBuilder Sınıfı yazısına taşıdım

Örnek - Delegated Advice
Açıklaması şöyle
... it is possible to instruct Byte Buddy to delegate to the advice methods instead. This can be controlled via the advice annotation attribute @Advice.OnMethodEnter(inline = false). By default, Byte Buddy will delegate to an advice method via a static method call.
Bu durumda kod şöyle olur
protected void service(HttpServletRequest req, HttpServletResponse resp) {
  long startTime = AdviceClass.enter();
  // original method body
  AdviceClass.exit(req, startTime);
}
2. invokedynamic-Based Advice Dispatching Approach
Bu yeni bir yaklaşım ve JVM'e eklenen invokedynamic sayesinde mümkün

5 Nisan 2021 Pazartesi

IntelliJ Idea ve Git

Log Penceresi
Semboller şöyle

Açıklaması şöyle
yellow: marks the current branch head

green: marks local branches

violet: marks remote branches
Yeşil yerel branch'ime yapılan commitleri gösterir.
Menekşe remote branch'lere yapılan commitleri gösterir. 
Yellow branch headini gösterir.

Örnek
Ben bir feature/2679'tayım branch'teyim. Ama filtre olarak origin/feature/22.1'i bakıyorum
origin branch'e kod merge edilmiş ancak daha ben pull etmemiş olayım. Şeklen şöyle görünür. Menekşe rengi yeni merge işlemini gösterir. # karakteri ile başlaması 3112 numaralı pull request'in merge olduğunu gösterir. Benim şu anki durumum ise sarı işaretli satırda.  Local branch'te bir commit gerideyim.

Benim feature/2679 origin'de silinmiş. Bu sefer şöyle görürüm. Bu sefer sarı etiket yok.

filtre ile local branch'e bakarsam şöyle. Yani en son commit'i almışım.

Eğer origin/feature/22.1'e geçersem ve her şeyi merge edersem görüntü şöyle



Common Local Branches
Eğer proje birden fazla repository kullanıyorsa, bu menü kullanılır. Böylece tüm repository'lere aynı anda Local Branch açılır ve bunlar birlikte push'lanabilir.

Aynı şeyi kendim kodla yapmak isteseydim tüm repositorlere teker teker
git -C "$path" checkout -b $new_branch_name 
komutunu çalıştırmak gerekirdi. Daha sonra push'larken IntelliJ kendisi remote branch açıyor.

GitHub
Projeyi Github üzerinde paylaşmak kolay. Şeklen şöyle




MapStruct @BeforeMapping Anotasyonu

Örnek
Şöyle yaparız. Bu kodda Foo nesnesinin speed değeri @BeforeMapping içinde Km/h olarak değiştiriliyor. Çünkü @BeforeMapping map işleminden önce çağrılır 
Daha sonra @AfterMapping içinde bar nesnesinin name alanı büyük harf haline getiriliyor.
@Mapper
public abstract class CarsMapper {
  @BeforeMapping
  protected void convertSpeed(Foo foo, @MappingTarget Bar bar) {
    foo.setSpeed (foo.getSpeed() * Units.MILE_TO_KM);    
  }

  @AfterMapping
  protected void convertNameToUpperCase(@MappingTarget CarDTO carDto) {
    bar.setName(bar.getName().toUpperCase());
  }

  public abstract Bar toBar(Foo foo);
}

MapStruct @Mapper Anotasyonu - Arayüzün Üstüne Yazılır

Giriş
Örnek
Şöyle yaparız. Burada INSTANCE alanı da kullanılarak CarMapper arayüzüne erişim daha kolay hale getiriliyor.
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface CarMapper {
    CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );

    CarDTO carToCarDto(Car car);
}
Örnek - Target İçindeki Alanı Parametre Geçmek
Elimizde şöyle bir kod olsun
class Foo {
  int field1;
}
class Bar {
  int field1;
  int sourceDevice;
}
Şöyle yaparız. Burada Bar içinde sourceDevice alanı metoda parameter olarak geçildiği için sorun olmuyor.
@Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR)
public interface FooMapper {
FooMapper INSTANCE = Mappers.getMapper(FooMapper.class);

Bar toBar(Foo foo, int sourceDevice);
}
componentModel Alanı
Açıklaması şöyle
Bonus Tip : There can be such cases where you need to perform some complex logic while mapping a field like Autowiring some other bean to your Mapper to get some information like active spring profiles by Autowiring Environment bean. In such cases you can’t use Interface as your mapper. Instead, use an Abstract class to declare your mapping methods as abstract methods.
Örnek - cdi
Şöyle yaparız
@Mapper(componentModel="cdi", injectionStrategy=InjectionStrategy.CONSTRUCTOR)
@Mapper(componentModel="spring", injectionStrategy=InjectionStrategy.FIELD)
Örnek - spring
Şöyle yaparız. Üretilen koda @Component anotasyonu eklenerek Spring bean'i olması sağlanır.
@Mapper(componentModel = "spring")
public interface DoctorMapper {
   DoctorDto toDto(Doctor doctor);
}
Örnek
Şöyle yaparız
@Mapper(componentModel = "spring")
public interface StudentMapper {
  StudentDto toDto(Student student);
}
Üretilen kod şuna benzer
import javax.annotation.Generated;
import org.springframework.stereotype.Component;

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2020-11-24T14:41:11+0100",
    comments = "version: 1.3.1.Final, compiler: javac, environment: Java 1.8.0_251
(Oracle Corporation)"
)
@Component
public class StudentMapperImpl implements StudentMapper {

  @Override
  public StudentDto toDto(Student student) {
    if ( student == null ) {
      return null;
    }

    StudentDto studentDto = new StudentDto();

    studentDto.setFirstname( student.getFirstname() );
    studentDto.setLastname( student.getLastname() );

    return studentDto;
  }
}
implementationPackage Alanı
Örnek
Şöyle yaparız. Üretilen kod "target/generated/sources/annotations/mapper/impl/" altına yerleştirilir.
@Mapper(implementationPackage = "mapper.impl")
public interface UserMapper {

  UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

  User userDTOtoUser(UserDto userDto);

  @InheritInverseConfiguration
  UserDto userToUserDTO(User user);
}
Kullanmak için şöyle yaparız
UserDto userDto = ...;
User user = UserMapper.INSTANCE.userDTOtoUser(userDto);
typeConversionPolicy Alanı
Açıklaması şöyle
Converting from larger data types to smaller ones (e.g. from long to int) can cause a value or precision loss. The Mapper annotation has a method typeConversionPolicy to control warnings / errors.
unmappedTargetPolicy Alanı
Eğe target sınıfın bir alanına değer atanmıyorsa, ne yapılacağını belirtir.
Örnek
Şöyle yaparız. Derleyici kodu derlemez.
@Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR)
public interface CarMapper {
   ...
}
uses Alanı
Not : uses alanını kullanmak istemiyorsakuses Alanı Seçeneği Yerine DTO yazısına bakabilirsiniz.

Örnek
Doctor sınıfında Address alanı varsa ve bunu DoctorDto sınıfındaki AddressDto alanına map'lemek istiyorsak şöyle yaparız
@Mapper(
      componentModel = "spring",
      unmappedTargetPolicy = ReportingPolicy.ERROR,
      uses = {AddressMapper.class})
public interface DoctorMapper {

   @Mapping(source = "phone", target = "contact")
   @Mapping(source = "speciality.name", target = "specialityName")
   DoctorDto toDto(Doctor doctor);
}
AddressMapper tabii ki bir Mapper olmalı. Şöyle yaparız
@Mapper(componentModel = "spring")
public interface AddressMapper {
   AddressDto toDto(Address address);
}