Apache Derby: Własne sortowanie tekstu (CollatorProvider)
Gdy w Apache Derby chcemy zastosować własne sortowanie tekstu musimy przygotować klasę kolatora rozszerzającą klasę CollatorProvider
.
Sposób przygotowania klasy został opisany w dokumentacji bazy. Moja klasa wygląda tak:
Klasa AriaCollatorProvider
package ariacollator; import java.text.*; import java.text.spi.*; import java.util.*; public class AriaCollatorProvider extends CollatorProvider { @Override public Collator getInstance(Locale locale) { StringBuilder rules = new StringBuilder(); rules.append( "<A,a<\u0104,\u0105<B,b<C,c<\u0106,\u0107<D,d<E,e<\u0118,\u0119<F,f<G,g"); rules.append( "<H,h<I,i<K,k<L,l<\u0141,\u0142<M,m<N,n<\u0143,\u0144<O,o<\u00D3,\u00F3"); rules.append("<P,p<Q,q<R,r<S,s<\u015A,\u015B<T,t<U,u<V,v<W,w"); rules.append("<X,x<Y,y<Z,z<\u0179,\u017A<\u017B,\u017C"); try { return new RuleBasedCollator(rules.toString()); } catch (ParseException e) { throw new Error(e); } } @Override public Locale[] getAvailableLocales() { return new Locale[]{Locale.of("te", "TE", "aria")}; } }
„te” – pochodzi od słowa terier
„TE” – pochodzi od słowa TERIEROGRÓD
„aria” – to dialekt sympatycznej terierki
Klasa jest umieszczona w module ariacollator
, którego układ wygląda tak (Rys. 1):
Plik module-info.java dla modułu wygląda tak:
module ariacollator { exports ariacollator; provides java.text.spi.CollatorProvider with ariacollator.AriaCollatorProvider; }
Zwróć uwagę na folder META-INF
zawierający folder services
, a w nim plik UTF-8 o nazwie java.text.spi.CollatorProvider
. Plik ma nazwę, ale nie posiada rozszerzenia. W pliku znajduje się jedna linijka zawierająca:
ariacollator.AriaCollatorProvider
Modułu możemy użyć bezpośrednio. Można tez utworzyć plik JAR i dodać do zależności.
Użyję klasy AriaCollatorMain
Klasa AriaCollatorMain
package aderby.attributes.collation; import aderby.DerbyUtil; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class AriaCollatorMain { private static final String baza = "C:/Przyklady/ariacol"; private static final String skrypt = "aderby/src/resources/sqls/teksty.sql"; public static void main(String[] args) { System.setProperty("java.locale.providers","SPI, CLDR, COMPAT"); DerbyUtil.startDerbyEngine(DerbyUtil.embdriver); Connection con = DerbyUtil.connectEmbeddedDB(baza, ";create=true;territory=te_TE_aria;collation=TERRITORY_BASED"); DerbyUtil.jdbcRunScript(skrypt, con); Statement stat = null; ResultSet rs = null; try { stat = con.createStatement(); rs = stat.executeQuery("SELECT * FROM dictionary "); while (rs.next()) { System.out.print(rs.getString("polski") + " "); } } catch (SQLException e) { e.printStackTrace(); } DerbyUtil.close(rs); DerbyUtil.close(stat); DerbyUtil.close(con); DerbyUtil.shutdownEmbeddedDB(baza); DerbyUtil.shutdownDerbyEngine(); } }
Zwróć uwagę na ustawienie zmiennej systemowej java.locale.providers
oraz na atrybuty połączenia:
territory=te_TE_aria;collation=TERRITORY_BASED
Znaczenie SPI, CLDR, COMPAT i innych znajduje się w opisie klasy LocaleServiceProvider
w dokumentacji Oracle.
Skrypt teksty.sql
CREATE TABLE dictionary( polski VARCHAR (30) ); CREATE INDEX i_polish ON dictionary (polski ASC); INSERT INTO dictionary VALUES ('E'); INSERT INTO dictionary VALUES ('e'); INSERT INTO dictionary VALUES ('O'); INSERT INTO dictionary VALUES ('o'); INSERT INTO dictionary VALUES ('L'); INSERT INTO dictionary VALUES ('l'); INSERT INTO dictionary VALUES ('S'); INSERT INTO dictionary VALUES ('s'); INSERT INTO dictionary VALUES ('A'); INSERT INTO dictionary VALUES ('a'); INSERT INTO dictionary VALUES ('Ą'); INSERT INTO dictionary VALUES ('ą'); INSERT INTO dictionary VALUES ('Ę'); INSERT INTO dictionary VALUES ('ę'); INSERT INTO dictionary VALUES ('Ó'); INSERT INTO dictionary VALUES ('ó'); INSERT INTO dictionary VALUES ('Ł'); INSERT INTO dictionary VALUES ('ł'); INSERT INTO dictionary VALUES ('ń'); INSERT INTO dictionary VALUES ('Ń'); INSERT INTO dictionary VALUES ('Ś'); INSERT INTO dictionary VALUES ('ś'); INSERT INTO dictionary VALUES ('C'); INSERT INTO dictionary VALUES ('Ć'); INSERT INTO dictionary VALUES ('ć'); INSERT INTO dictionary VALUES ('c'); INSERT INTO dictionary VALUES ('n'); INSERT INTO dictionary VALUES ('N'); INSERT INTO dictionary VALUES ('Z'); INSERT INTO dictionary VALUES ('Ż'); INSERT INTO dictionary VALUES ('ź'); INSERT INTO dictionary VALUES ('Ź'); INSERT INTO dictionary VALUES ('z'); INSERT INTO dictionary VALUES ('ż');
Powyższa klasa znajduje się w innym module tego samego projektu.
Plik module-info.java
musi zawierać:
requires ariacollator; uses ariacollator.AriaCollatorProvider;
Po uruchomieniu klasy na konsoli zobaczymy:
A a Ą ą C c Ć ć E e Ę ę L l Ł ł N n Ń ń O o Ó ó S s Ś ś Z z Ź ź Ż ż
I to jest dokładnie ten sposób sortowania, który chcieliśmy osiągnąć.
Pliki do ściągnięcia
Aktualny (tworzony narastająco) plik module-info.java
Aktualny (tworzony narastająco) plik DerbyUtil.java
Pliki tworzone narastająco zastępują poprzednie pliki o tej samej nazwie i działają dla wszystkich wcześniej opublikowanych przykładów we wszystkich wpisach w projekcie. W przypadku pliku module-info.java
może być potrzebne skreślenie niepotrzebnych wpisów.