30 Haziran 2020 Salı

RSAPublicKeySpec Sınıfı

Giriş
PublicKey içinde Modulus+Public Exponent bilgisi bulunur.

Örnek
Şöyle yaparız
public PublicKey getPublicKey(BigInteger mod, BigInteger pubExp)
  throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidRsaKey {

  RSAPublicKeySpec keySpec = new RSAPublicKeySpec(mod, pubExp);
  KeyFactory fact = KeyFactory.getInstance("RSA");
  PublicKey pubKey = fact.generatePublic(keySpec);
  return pubKey;
}

RSAPrivateKeySpec Sınıfı

Giriş
Private key içinde Modulus+Public Exponent+Private Exponent bilgisi vardır. Public exponent üretiliyor sanırım.

Örnek
Şöyle yaparız
public PrivateKey getPrivateKey(BigInteger mod,BigInteger pvtExp)
  throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidRsaKey {

  RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(mod, pvtExp);
  KeyFactory fact = KeyFactory.getInstance("RSA");
  PrivateKey privKey = fact.generatePrivate(keySpec);
  return privKey;
}

29 Haziran 2020 Pazartesi

Hibernate'e Mahsus JPA @Lob Anotasyonu - PostgreSQL

Giriş
Bu yazı JPA sağlayıcısı olarak Hibernate kullanıldığında olan şeylerle ilgili. Özet olarak şöyle yapmak lazım. Neden böyle gerektiği ise yazının devamında
@Entity
public class Exam {

  @Lob
  private String description; //Bu işe yaramıyor
}

@Entity
public class Exam {

  @Column(columnDefinition="TEXT")
  private String text; //Böyle yapmak lazım
}
Detaylar
Blob tipini Java kodu içinde saklamak için genelde üye alan olarak iki tip kullanılıyor.
1. byte []
2. String

Eğer üye alana byte[] ise PostgreSQL BLOB veriyi saklamak için iki farklı sütun sağlar. Bunlar şöyle.
bytea - data stored in table
oid - table holds just identifier to data stored elsewhere
Eğer üye alana String ise  PostgreSQL CLOB veriyi saklamak için iki farklı sütun sağlar. Bunlar şöyle.
text
oid

OID Nedir?
Açıklaması şöyle
PostgreSQL provides two distinct ways to store binary data. Binary data can be stored in a table using the data type BYTEA or by using the Large Object feature, which stores the binary data in a separate table in a special format and refers to that table by storing a value of type OID in your table. 
OID için bir başka açıklama şöyle.
A column of type Oid is just a reference to the binary contents which are actually stored in the system's pg_largeobject table. In terms of storage, an Oid a 4 byte integer. On the other hand, a column of type bytea is the actual contents.

Problem Nedir?
Burada problem Hibernate'in varsayılan davranış  olarak hep  OID kullanması ve veriyi PG_LARGEOBJECT tablosunda saklaması

Bu davranışı istemiyoruz çünkü kendi tablomuzdaki satır silinse bile PG_LARGEOBJECT tablosundaki satır silinmez. Açıklaması şöyle.
LOBs are NOT deleted from the database when the rows of your application table (containing the OIDs) get deleted.

This also means that space will NOT be reclaimed by the VACUUM process.

In order to get rid of unused LOBs, you have run VACUUMLO on the databases. Vacuumlo will delete all of the unreferenced LOBs from a database.
Bu orphan satırları silmek için VACUUMLO komutu kullanılır.

1. Üye Alan Tipi byte [] İse
Eğer değişken tipi byte [] ise JDBC olarak java.sql.Types.BLOB seçilir.  Hibernate şöyle yapar. Yani varsayılan sütun tipi oid tipidir.
public PostgreSQLDialect() {
    super();
    ...
    registerColumnType(Types.VARBINARY, "bytea");
    /**
      * Notice it maps java.sql.Types.BLOB as oid
      */
    registerColumnType(Types.BLOB, "oid");
}
bytea Sütun Tipi İle Çalışmak - İstenilen Davranış
bytea binary string anlamına gelir.

Örnek
Eğer sütun tipi bytea ise sütunu yaratmak için şöyle yaparız.
public class Template {
  ...

  @Lob
  @Column(columnDefinition="bytea")
  private byte[] data;
}
Örnek
Eğer sütun tipi bytea ise okuyup yazmak için şöyle yaparız.
@Lob
@Column(name="image")
@Type(type="org.hibernate.type.BinaryType")
private byte[] image;
2. Üye Alan Tipi String İse
Elimizde şöyle bir kod olsun
@Entity  
@Table(name = "document")  
public class Document {  
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id", nullable = false)
  private Long id;
 
  @Column(name = "date_created", nullable = false)
  private LocalDateTime dateCreated;
 
  @Column(name = "doc_txt")
  private String docText;
   
  //Getters and setters omitted for brevity
}  
Burada veri tabanındaki sütunun varsayılan uzunluğu 255. Açıklaması şöyle
In Java, the string datatype can hold about 2Gb of text data, but the table column size will be limited to 255 characters by default for the model above.
 Dolayısıyla eğer uzun bir String tipi kaydederken org.postgresql.util.PSQLException: ERROR: value too long for type character varying(255) hatası alabiliriz. 

2.1 @Lob Olarak İşaretlemek - İstemiyoruz
Biz de sütunumuzu @Lob ile işaretlemeye karar veririz. Bu durumda üye alan için ise JDBC tiplerinden java.sql.Types.CLOB seçilir. PostgreSQL CLOB sütunu olarak text tipini kullanır. Ancak Hibernate String'i de aynı oid gibi başka bir alanda saklar!

Örnek
Elimizde şöyle bir kod olsun.
@Column(name = "doc_txt")
@Lob
private String docText;
Hibernate tarafından üretilen SQL şöyledir
CREATE TABLE document ( 
  id INT8 GENERATED BY DEFAULT AS IDENTTITY, 
  date_created TIMESTAMPT NOT NULL, 
  doc_txt OID, 
  PRIMARY KEY (id) 
); 
Eğer tabloya bakarsak veri şöyledir
SELECT * FROM document

id	date_created		doc_txt
1	2020-01-01 10:10:00	76388
Yani veri başka tabloda. Veriyi görmek için şöyle yaparız
SELECT * FROM pg_largeobject WHERE loid=76338
Örnek
Elimizde şöyle bir kod olsun.
@Column(name = "xml")
@Lob
private String xml;
Bu tabloya bakarsak xml sütunu text tipindendir.
Column     |            Type             | Modifiers 
 ----------------+-----------------------------+-----------
 xml       | text                        | 
xml sütunundaki veriye bakarsak oid değer görürüz.
# select * from  tablename
xml
+------------
 242781
(1 row)
2.2 Text Sütun Tipi İle Çalışmak - İstenilen Davranış
Örnek - Kolay yol
String'i tablo içinde saklamak için şöyle yaparız
@Column(columnDefinition="text")
private String column;
Açıklaması şöyle. Yani 1 GB civarında metin saklanabilir.
.. , the longest possible character string that can be stored is about 1 GB
...
It is smaller than 4Gb, allowed by LOB storage, but still long enough for most use cases.

Örnek - Hibernate 6
Şöyle yaparız
@Column(name = "doc_txt", length = Length.LOB_DEFAULT)   
private String docText; 
Açıklaması şöyle. Yani sütun TEXT tipinden olmuyor
In Hibernate 6, the org.hibernate.type.TextType class was removed. To define a column to store a long text, we can define the attribute in the following way:

This will give us the following column definition in the database: doc_txt varchar(1048576). It is not the TEXT datatype, but it can still store about 1Gb of text in the table. It is the largest possible character string in PostgreSQL.
Yani sütun TEXT tipinden olsun istersek şöyle yaparız
@JdbcTypeCode(SqlTypes.LONG32VARCHAR)   
@Column(name = "doc_txt")   
private String docText;
Örnek - Hibernate 5 Anotasyonu
Açıklaması şöyle. Bu sınıfın eski ismi org.hibernate.type.StringClobType şeklindeydi. Sonrada isim değiştirdi.
The Hibernate @Type value that maps to PG's Text data type is org.hibernate.type.TextType. This is what you should use.
String'i tablo içinde saklamak için bir tane daha Hibernate anotasyonu ekleriz. Şöyle yaparız.
@Type(type="org.hibernate.type.TextType")
Örnek
Şöyle yaparız
@Type(type = "org.hibernate.type.TextType")   
@Column(name = "doc_txt")   
private String docText;

28 Haziran 2020 Pazar

SAX InputSource Sınıfı

Giriş
Şu satırı dahil ederiz.
import org.xml.sax.InputSource;
SAXSource sınıfının yaratmak için gerekir. InputStream veya Reader arayüzlerinin SAXSource tarafından okunabilmesini sağlar.

24 Haziran 2020 Çarşamba

HashSet Sınıfı - Comparator Verilemez

Giriş
Şu satırı dahil ederiz.
import java.util.HashSet;
Set arayüzünden kalıttığı için şöyle yaparız.
Set<Integer> set = new HashSet<>();
Comparator
Bu sınıfa Comparator verilemediği için TreeSet tercih edilebilir.

Örnek
Şöyle yaparız
TreeSet<String> treeSet = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
HashSet<String> hashSet = new HashSet<>();
treeSet.addAll(List.of("A", "b"));
hashSet.addAll(List.of("A", "B"));
System.out.println(hashSet.equals(treeSet)); // false
System.out.println(treeSet.equals(hashSet)); // true
Açıklaması şöyle. TreeSet açısından HashSet'teki tüm elemanlar kendinde mevcut çünkü Comparator kullanıyor.
The reason for this is that a TreeSet uses comparator to determine if an element is duplicate while HashSet uses equals.
constructor - default
Şöyle yaparız.
HasSet<Integer> set = new HashSet<>();
constructor - capacity + loadfactor
Bu sınıf altta HashMap Sınıfını kullanır. Metodun için şöyledir.
public HashSet(int initialCapacity, float loadFactor) {
    map = new HashMap<>(initialCapacity, loadFactor);
}
Şöyle yaparız.
HashSet <Integer> set = new HashSet<> (10,0.5);
constructor  - Collection
Metodun içi şöyle. Önce bir map oluşturulur. Daha sonra her şey map'e eklenir.
public HashSet(Collection<? extends E> c) {
  map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
  addAll(c);
}
Örnek
Listeyi ekleyerek çiftleri elememek için şöyle yaparız.
Set<String> set = new HashSet<>(list);
add metodu
Ekleme başarılı ise true döner. Değer zaten varsa false döner.
Örnek
Şöyle yaparız.
HashSet<Integer> set = ...;
int item = ...;
if (!set.add(item)) {
  //Duplicate;
}
Daha kolay anlaşılır kod için şöyle yapmak gerekir.
boolean added = set.add(entry);

if (added) {
    //do some more stuff
}
Metodun içi şöyledir. PRESENT dummy bir değerdir.
public boolean add(E e) {
  return map.put(e, PRESENT)==null;
}
addAll metodu
Listeyi ekleyerek çiftleri elememek için şöyle yaparız.
set.addAll(list);
removeAll metodu
over200 olanları geri kalandan silmek için şöyle yaparız.
Set<Laptops> over2000 = ...;
Set<Laptops> rest = ...;
rest.removeAll(over2000);
retainAll metodu
İki set'in kesişimini verir.
Örnek
Şöyle yaparız.
public Integer[] intersection(int[] nums1, int[] nums2) {

  HashSet<Integer> set1 = new HashSet<>();
  for(int i : nums1) {
    set1.add(i);
  }

  HashSet<Integer> set2 = new HashSet<>();
  for(int i : nums2) {
    set2.add(i);
  }

  set1.retainAll(set2);

  return set1.toArray(new Integer[set1.size()]);
}
Örnek
Elimizde iki dizi olsun nums1 = [1, 2, 2, 1], nums2 = [2, 2],
Çıktı olarak kesişim olan [2] sonucunu alırız.

Örnek
Şöyle yaparız.
Set<String> set1 = new HashSet<String>(coll1);
Set<String> set2 = new HashSet<String>(coll2);

set1.retainAll(set2); //gives me an empty set
toArray metodu - T[]
Girdi olarak verilen array HashSet'in büyüklüğünden küçükse yeni bir array döner.
Örnek
Elimizde şöyle bir kod olsun.
Set<Integer> x = new HashSet<>();
x.add(4);
Şöyle yaparız.
Integer[] arr = x.toArray(new Integer[x.size()]);
Diğer
HashSet'in Kendini İçermesi
Açıklaması şöyle.
"it is not permissible for a set to contain itself as an element"
Açıklaması şöyle.
Some collection operations which perform recursive traversal of the collection may fail with an exception for self-referential instances where the collection directly or indirectly contains itself. This includes the clone()equals()hashCode() and toString() methods. Implementations may optionally handle the self-referential scenario, however most current implementations do not do so.
Şöyle yapmamak lazım.
Set<Object> mySet = new HashSet<>();
mySet.add(mySet);
Şöyle de yapmamak lazım.
Set<Object> setA = new HashSet<Object>();
Set<Object> setB = new HashSet<Object>();
setA.add(setB);
setB.add(setA);