21 Temmuz 2023 Cuma

JPA @Converter Anotasyonu - Custom Conversion

Giriş
Şu satırı dahil ederiz.
import javax.persistence.Converter;
Kendi yazdığım AttributeConverter arayüzünden kalıtan sınıfı JPA'ya tanıtmak içindir.

autoApply Alanı False İse
İlgili alan üzerinde kullanmak gerekir. Şöyle yaparız
@Converter(converter=LocalDateTimePersitenceConverter.class)
autoApply Alanı True İse
Eğer her alana otomatik uygunlansın istersek şöyle yaparız.
@Converter(autoApply = true)
public class LocalDateAttributeConverter implements AttributeConverter<LocalDate, Date> {

  @Override
  public Date convertToDatabaseColumn(LocalDate locDate) {
    return (locDate == null ? null : Date.valueOf(locDate));
  }

  @Override
  public LocalDate convertToEntityAttribute(Date sqlDate) {
    return (sqlDate == null ? null : sqlDate.toLocalDate());
  }
}
Örnek
Elimizde şöyle bir Enum olsun
public enum Status {
  ACTIVATED(1), DEACTIVATED(2), SUSPENDED(3);

  int statusId;

  private Status(int statusId) {
    this.statusId = statusId;
  }

  public int getStatusId() {
    return statusId;
  }
};
Şöyle yaparız
@Converter
public class CustomerStatusConverter implements 
  AttributeConverter<Status, Integer> {
  @Override
  public Integer convertToDatabaseColumn(Status status) { 
    return status.getStatusId();
  }

  @Override
  public Customer.Status convertToEntityAttribute(Integer statusId) {
    return Arrays.stream(Status.values())
      .filter(s -> s.getStatusId() == statusId)
      .findFirst()
      .orElseThrow(IllegalArgumentException::new);
  }
}

@Entity
public class Customer {
  @Convert(converter = CustomerStatusConverter.class)
  private Status status;
  ...
}


JDBC Enum String İçin Posgtre'ye Özel Çözümler

Örnek
Elimizde şöyle bir PostgreSQL tablosu olsun. Burada order_status isimli yeni bir type yarattık.
CREATE TYPE order_status AS ENUM(
  'Ordered', 
  'Baking', 
  'Delivering', 
  'YummyInMyTummy');

CREATE TABLE pizza_order (
  id INT PRIMARY KEY,
  status order_status NOT NULL,
  order_time TIMESTAMP NOT NULL DEFAULT now()
);
Bu type aslında Java kodu olarak şöyle
public enum OrderStatus {
  Ordered,
  Baking,
  Delivering,
  YummyInMyTummy
}
Şu SQL çalışır, çünkü status tipi olarak CREATE TYPE ile belirtilen bir string verdik
INSERT INTO pizza_order (id, status, order_time) 
VALUES (1, 'Ordered', now());
Ama JDBC olarak çalışmaz
PreparedStatement statement = conn
  .prepareStatement("INSERT INTO pizza_order (id, status, order_time) VALUES(?,?,?)");

statement.setInt(1, 1);
statement.setString(2, OrderStatus.Ordered.toString());
statement.setTimestamp(3, Timestamp.from(Instant.now()));

statement.executeUpdate();
Hata şöyle. Yani veri tabanı varchar'ı status type'a nasıl çevireceğini bilmiyor.
org.postgresql.util.PSQLException: ERROR: column "status" is of type order_status but expression is of type character varying
Hint: You will need to rewrite or cast the expression.
Çözüm 1
java.sql.Types.OTHER kullanırız.
PreparedStatement statement = conn
  .prepareStatement("INSERT INTO pizza_order (id, status, order_time) VALUES(?,?,?)");

statement.setInt(1, 1);
statement.setObject(2, OrderStatus.Ordered, java.sql.Types.OTHER);
statement.setTimestamp(3, Timestamp.from(Instant.now()));

statement.executeUpdate();
Çözüm 2
String olarak geçebilmek için CAST yaratılır. 
CREATE CAST (varchar AS order_status) WITH INOUT AS IMPLICIT;
O zaman hem JDBC ile enum'u string olarak yazabiliriz, hem de String'i Java Enum olarak okuyabiliriz. Yazma için şöyle yaparız
PreparedStatement statement = conn
  .prepareStatement("INSERT INTO pizza_order (id, status, order_time) VALUES(?,?,?)");

statement.setInt(1, 1);
statement.setString(2, OrderStatus.Ordered.toString());
statement.setTimestamp(3, Timestamp.from(Instant.now()));

statement.executeUpdate();
Okuma için şöyle yaparız
PreparedStatement statement = conn.prepareStatement("SELECT id, status, order_time " +
	"FROM pizza_order WHERE id = ?");
statement.setInt(1, 1);

ResultSet resultSet = statement.executeQuery();
resultSet.next();

PizzaOrder order = new PizzaOrder();

order.setId(resultSet.getInt(1));
order.setStatus(OrderStatus.valueOf(resultSet.getString(2)));
order.setOrderTime(resultSet.getTimestamp(3));

JPA @Enumerated Anotasyonu

Giriş
Şu satırı dahil ederiz.
import javax.persistence.Enumerated;
Açıklaması şöyle.
ORDINAL: Persist enumerated type property or field as an integer.
STRING: Persist enumerated type property or field as a string.
@Enumerated anotasyonu EnumType.X şeklinde kullanılır. EnumType.STRINGise enum'un string değeri veri tabanına yazılır. EnumType.ORDINAL ise sayısal bir değer yazılır.

Not : JPA @Converter Anotasyonu ile custom conversion da yapılabilir

1. EnumType.ORDINAL
Örnek
Şöyle yaparız.
@Enumerated(EnumType.ORDINAL)
private Role userRole;
2. EnumType.STRING

Örnek
Açıklaması şöyle.
Remember JPA uses the name() of the enum and not the toString() even if you have overridden the toString().
Elimizde şöyle bir enum olsun. Veritabanına "PRIMARY_ACCOUNT" string olarak yazılır. "Primary customer" değil.
public enum AccountRole {
  EMPLOYEE_CUSTOMER("Employee customer"),
  JOINTER_ACSCOUNT("Jointer customer"),
  PRIMARY_ACCOUNT("Primary customer"),
  TENANT_ACCOUNT("Tenant customer");

  private final String text;

  AccountRole(final String text) {
    this.text = text;
  }

  @Override
  public String toString() {
    return text;
  }
}
Örnek
Şöyle yaparız:
@Enumerated(EnumType.STRING)
@Column(name = "LOGIC")
public BusinessLogic getLogic(){...usual getter...}



13 Haziran 2023 Salı

Artemis EmbeddedActiveMQResource Sınıfı - Unit Test İçindir

Giriş
Şu satırı dahil ederiz
import org.apache.activemq.artemis.junit.EmbeddedActiveMQResource;
Açıklaması şöyle
Run a Server, without the JMS manager
Açıklaması şöyle
EmbeddedActiveMQResource is a class provided by the artemis-junit dependency, which allows you to easily set up an embedded ActiveMQ Artemis server for unit testing.
Maven
Şu satırı dahil ederiz. 
1. artemis-jakarta-server birim test içinde ActiveMQConnectionFactory gibi sınıfları kullanmak için gerekir. Yani parent POM gibi düşünülebilir. Kodu burada. İçinden artemis-junit çıkmıyor. Dolayısıyla bunu eklemek lazım
2. artemis-junit içinde bazı şeyleri dışarıda bırakmak gerekiyor, çünkü bu kütüphane güncellenmemiş ve javax.jms isim alanındaki sınıfları da getiriyor. Ama biz jakarta.jms isim alanını kullanmak istiyoruz
<dependency>
  <groupId>org.apache.activemq</groupId>
  <artifactId>artemis-jakarta-server</artifactId>
  <version>5.15.11</version>
  <type>pom</type>
  <scope>test</scope>
</dependency>

<dependency>
  <groupId>org.apache.activemq</groupId>
  <artifactId>artemis-junit</artifactId>
  <version>5.15.11</version>
  <scope>test</scope>
  <!-- Exclude dependencies that bring in jms namespace -->
  <exclusions>
    <exclusion>
      <groupId>org.apache.activemq</groupId>
      <artifactId>artemis-jms-client</artifactId>
    </exclusion>
  </exclusions>
</dependency>
createQueue metodu
Örnek
JUnit4 ile şöyle yaparız
public class MyTest {
  @Rule
  public EmbeddedActiveMQResource server = new EmbeddedActiveMQResource();

  @Test
  public void myTest() {
    // test something, eg. create a queue
    server.createQueue("test.adress", "test.queue");
  }
}
JUnit5 ile şöyle yaparız
public class MyTest {
   @RegisterExtension
   public EmbeddedActiveMQExtension server = new EmbeddedActiveMQExtension();

   @Test
   public void myTest() {
     // test something, eg. create a queue
     server.createQueue("test.adress", "test.queue");
   }
}
getVmURL metodu
Örnek
Şöyle yaparız. Burada createSession(false,Session.AUTO_ACKNOWLEDGE) ile transaction kullanmayan ve hemen onaylanan bir Session başlatılıyor
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.apache.activemq.junit.EmbeddedActiveMQBroker;

import jakarta.jms.Connection;
import jakarta.jms.ConnectionFactory;
import jakarta.jms.JMSException;
import jakarta.jms.MessageProducer;
import jakarta.jms.Queue;
import jakarta.jms.Session;
import jakarta.jms.TextMessage;
import static org.junit.Assert.assertNotNull;

public class ArtemisUnitTest {
  @Rule
  public EmbeddedActiveMQBroker broker = new EmbeddedActiveMQBroker();
  @Test
  public void testSendMessage() throws JMSException {
    ConnectionFactory connectionFactory = createConnectionFactory();
    try (Connection connection = connectionFactory.createConnection()) {    
      Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
      Queue queue = session.createQueue("exampleQueue");
      MessageProducer producer = session.createProducer(queue);
      TextMessage message = session.createTextMessage();
      message.setText("Hello, Artemis!");
      producer.send(message);
      // Verify that the message was sent successfully
      assertNotNull(message.getJMSMessageID());
    }
  }
  private ConnectionFactory createConnectionFactory() {
    String brokerUrl = broker.getVmURL();
return new ActiveMQConnectionFactory(brokerUrl); } }
Örnek
Şöyle yaparız. Burada createSession(false,Session.DUPS_OK_ACKNOWLEDGE) ile transaction kullanmayan ve mesajların çift gelebileceği bir Session başlatılıyor
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.apache.activemq.artemis.jms.client.ActiveMQXAConnectionFactory;
import org.apache.activemq.junit.EmbeddedActiveMQBroker;

import jakarta.jms.Connection;
import jakarta.jms.ConnectionFactory;
import jakarta.jms.JMSException;
import jakarta.jms.Message;
import jakarta.jms.MessageConsumer;
import jakarta.jms.Session;
import jakarta.jms.TextMessage;

public class ArtemisUnitTest {
  @ClassRule
  public static EmbeddedActiveMQResource broker = new EmbeddedActiveMQResource();

  @Test
  public void foo () {
    try (
      Connection connection = new ActiveMQConnectionFactory(broker.getVmURL())
        .createConnection();
      Session session = connection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
      MessageConsumer consumer = session
        .createConsumer(session.createQueue(destinationName))
    ) {
      ...
    });
  }
}



31 Mayıs 2023 Çarşamba

MicroStream - Persistence Framework

Maven
Şu satırı dahil ederiz
<dependency>
   <groupId>expert.os.integration</groupId>
   <artifactId>microstream-jakarta-data</artifactId>
   <version>${microstream.data.version}</version>
</dependency>
<dependency>
    <groupId>one.microstream</groupId>
    <artifactId>microstream-afs-sql</artifactId>
    <version>${microstream.version}</version>
</dependency>
<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.2.14</version>
</dependency>
Örnek
Şöyle yaparız
@ApplicationScoped
class DataSourceSupplier implements Supplier<DataSource> {
  private static final String JDBC = "microstream.postgresql.jdbc";
  private static final String USER = "microstream.postgresql.user";
  private static final String PASSWORD = "microstream.postgresql.password";

  @Override
  @Produces
  @ApplicationScoped
  public DataSource get() {
    Config config = ConfigProvider.getConfig();
    PGSimpleDataSource dataSource = new PGSimpleDataSource();
    dataSource.setUrl(config.getValue(JDBC, String.class));
    dataSource.setUser(config.getValue(USER, String.class));
    dataSource.setPassword(config.getValue(PASSWORD, String.class));
    return dataSource;
  }
}

@Alternative
@Priority(Interceptor.Priority.APPLICATION)
@ApplicationScoped
class SQLSupplier implements Supplier<StorageManager> {

  @Inject
  private DataSource dataSource;

  @Override
  @Produces
  @ApplicationScoped
  public StorageManager get() {
    SqlFileSystem fileSystem = SqlFileSystem.New(
      SqlConnector.Caching(
        SqlProviderPostgres.New(dataSource)
      )
    );
   return EmbeddedStorage.start(fileSystem.ensureDirectoryPath("microstream_storage"));
  }

  public void close(@Disposes StorageManager manager) {
    manager.close();
  }
}
Kullanmak için şöyle yaparız
@Repository
public interface Airport extends CrudRepository<Airplane, String> {
    List<Airplane> findByModel(String model);
}

@Entity
public class Airplane {
    @Id
    private String id;
    @Column("title")
    private String model;
    @Column("year")
    private Year year;

    @Column
    private String manufacturer;
}

try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
    Airplane airplane = ...;
    Airplane airplane2 = ...;
    Airplane airplane3 = ...;
    Airplane airplane4 = ...;
    Airplane airplane5 = ...;
    Airport airport = container.select(Airport.class).get();
    airport.saveAll(List.of(airplane, airplane2, airplane3, airplane4, airplane5));
    var boings = airport.findByModel(airplane.getModel());
    var all = airport.findAll().toList();
    System.out.println("The boings: " + boings);
    System.out.println("The boing models avialables: " + boings.size());
    System.out.println("The airport total: " + all.size());
}




Object Model API For JSON

Giriş
Yeni paket ismi jakarta.json. Açıklaması şöyle
The javax.json package provides an Object Model API to process JSON. The Object Model API is a high-level API that provides immutable object models for JSON object and array structures. 
These JSON structures can be represented as object models using JsonObject and JsonArray interfaces.
Açıklaması şöyle
The Javax.json package is a collection of all the utilities that are available for use in Java environments to process JSON. It includes facilities such as getting immutable objects or event streams by parsing input streams, feeding output streams with these immutable objects or event streams, building immutable objects using builders, and navigating immutable objects.
Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>org.glassfish</groupId>
  <artifactId>javax.json</artifactId>
  <version>1.1.2</version>
</dependency>
JsonGenerator Arayüzü
Açıklaması şöyle
We can use the JsonGenerator interface to write the JSON data to an output in a streaming way. 
JsonReader Arayüzü
read metodu
Örnek
Şöyle yaparız
// Read json and create get the structure from it
JsonReader reader = Json.createReader(new FileReader("src/main/resources/profile.json"));
JsonStructure jsonStructure = reader.read();
JsonPointer Arayüzü
Bir anlamda XPATH gibidir.

add metodu
Örnek
Şöyle yaparız
JsonStructure jsonStructure = ...

// add a new value
JsonPointer agePointer = Json.createPointer("/age");
JsonNumber age = Json.createValue(30);
jsonStructure = agePointer.add(jsonStructure, age);
System.out.println(jsonStructure);

JsonPointer skillsPointer = Json.createPointer("/skills/-");
JsonString skill = Json.createValue("JsonPointer");
jsonStructure = skillsPointer.add(jsonStructure, skill);
System.out.println(jsonStructure);
containsValue metodu
Örnek
Şöyle yaparız
JsonStructure jsonStructure = ...

// checking a key exists
JsonPointer fakeKeyPointer = Json.createPointer("/fake");
boolean found = fakeKeyPointer.containsValue(jsonStructure);
System.out.println(found);

JsonPointer outOfBounds = Json.createPointer("/projects/3");
boolean foundOOB = outOfBounds.containsValue(jsonStructure);
System.out.println(foundOOB);
getValue metodu
Örnek
Şöyle yaparız
JsonStructure jsonStructure = ...

// getting a value from path

// using just object keys
JsonPointer cityPointer = Json.createPointer("/address/city"); 
JsonString city = (JsonString) cityPointer.getValue(jsonStructure);
System.out.println(city.getString());

// using just array indexes
JsonPointer projectTwoPointer = Json.createPointer("/projects/1"); 
JsonObject project = (JsonObject) projectTwoPointer.getValue(jsonStructure);
System.out.println(project.toString());
remove metodu
Örnek
Şöyle yaparız
JsonStructure jsonStructure = ...

// remove a field
JsonPointer addressPointer = Json.createPointer("/address");
jsonStructure = addressPointer.remove(jsonStructure);
System.out.println(jsonStructure);
replace metodu
Örnek
Şöyle yaparız
JsonStructure jsonStructure = ...

// change a value
JsonPointer namePointer = Json.createPointer("/name");
JsonString name = Json.createValue("Bill Nye");
jsonStructure = namePointer.replace(jsonStructure, name);
System.out.println(jsonStructure);

Bean Validation @GroupSequence Anotasyonu

Örnek Elimizde şöyle bir kod olsun public class SampleRequest {   @NotNull   LocalDate startDate;   @NotNull   LocalDate endDate;   @AssertT...