Metoda final w interface

0

Jak to zrobić ładnie ?

Kontekst: klasy implementowane z tego interfejsu będą zasilały bibliotekę templejtową (akurat StringTemplate, ale ztcw wszystkich dotyczy)
Biblioteka tego typu oczekuje propertisów w konwencji beanowej getXxxxxxxx
Nie uwzględnia Optionali, czysty tradycyjny null pozwala zrobić generowanie warunkowe.

Przerabiamy >15 letni kod z javy przed 8 i Velocity, która generuje HTMLki.
W generowanej tabelce HTML jest opcjonalny element caption - opcjonalność pomyślałem wyrazić jako Optional, i to mi się podoba, klient tego interfejsu wypełni implementację, lub nie.
Nie podoba mi się metoda o prefiksie get, konieczna ze względu na bibliotekę - zakaz jej implementowania bym wyraził przez final , ale nie jest dopuszczalne.

public interface ITableModel<T, C extends IColumnHeader> {
 ...
     default public Optional<String> someCaption()  { return Optional.empty(); }
     /*final*/ default String getCaption() { return  someCaption().isPresent()? someCaption().get() : null;
}


PS. To początek, ale bardzo mi się podoba "matematyczna" wręcz czystość modelu StringTemplate - velocity pozwalała na architektoniczne syfki, setowanie z templete, "naprawianie" niedostatków modelu itd...

5

A jakby tak tę metodę oznaczyć jako static i elo?

0
Pinek napisał(a):

A jakby tak tę metodę oznaczyć jako static i elo?

Ale pracuje z this. A danie argumentu zamiast this nie spełnia konwencji beanowej. Próbowałem

Aha, może oczywiste, może nie, jest ratunek w klasie abstrakcyjnej pierwsze piętro nad interface'm - ale cała elegancja projektowanie wg interfaców idzie się pie..

2

Coraz bardziej wydaje mi się, że problem jest trochę na siłę, ale skoro static nie pasuje, to może wyodrębnij tę metodę do osobnej klasy abstrakcyjnej i oznacz ją jako final wtedy?

0

To pójdzie chyba w jakby Decorator (mniej czy bardziej ortodoksyjny, jeden z nich z klasa abstrakcyjną). Życie pokazuje jeszcze dwie - trzy bardzo podobne property

public interface ITableModel<T, C extends IColumnHeader> {
 ...
     default public Optional<String> someCaption()  { return Optional.empty(); }
   
}


public abstract class TableModelDecorator {
  TableModelDecorator (ITableModel itm);
  {
      this.oryginalModel = itm
  }
  public final String getCaption() { return  oryginalModel .isPresent()? oryginalModel.get() : null; }
} 

lub

public abstract class TableModelDecorator implements ITableModel {
  public final String getCaption() { return  someCaption().isPresent()? someCaption().get() : null; }
} 

Jeszcze nie wiem ;) W ogóle z frajdą to traktuję jak zagadkę.

Z perspektywy templatki bym chciał uniknąć zbyt dużego poziomu zagłębienia (zbyt dużo kropek, żeby nie zarypać frontmana) - wolałbym zawieranie a nie dziedziczenie, ALE z automatycznym proxy do klasy wewnętrznej, aby skrócić o "kropkę" *)
Java jest językiem statycznie typowanym, od strony templatki raczej się to widzi dynamicznie, bez wódki trudno to rozebrać ;)

*) proxy to brzmi strasznie ambitnie, ale to tu w odniesieniu do template mam nadzieję to będzie proste ... ale to po porannej kawie

0

Ja bym zrobił to tak:

  • Prawie każdy template do renterowania txt ma możliwość przekazania mapy Map<String, Object> zamiast beana
  • Maperem ze wsparciem dla Optional<T> zrzucił bym beana do Map<String, Object>
  • Mapę przekazał bym do liba templateu

Można też wyrzeźbić ten kawałek kodu ręcznie. Wtedy jedna klasa konwerter Bean -> Mapa (pewnie jest i do tego libka) załatwia wszystkie klasy do renderowania.

Ale jest jeszcze jedna droga, można poszukać czy istnieje możliwość wpięcia się w samą bibliotekę renderującą. Być może jest jakiś ValueProvider czy inny byt który można podmienić tak żeby przekonwertować Optional na odpowiednią wartość.

1

@0xmarcin:

Ciepło, ciepło.

Ze zdziwieniem dowiedziałem się, ze StringTemplate nie ma *1) *in-the-box kompatybilności z Map (tego oczekiwałem, wszystkie inne libki miały - bo osłabia "ortodoksyjność" projektu) , ale implementuje się przewidziane rozszerzenie ModelAdaptor (żeni się z typem "rekordu").
Właśnie tym adapterem skracam nazwy o "kropkę", z $model.internal.cokolwiek$ na $model.cokolwiek$

Czy jest coś jak nazwałeś ValueProvider, rozszerzenie żenione z typem property, właśnie czytam. A w zasadzie dekodowanie Optionala da się wsadzić w powyższy Adapter, raz na wszelkie przypadki użycia.

*1) *mimo, ze czegoś nie ma, coraz bardziej mi się podoba https://www.stringtemplate.org/. To jest zaprojektowane przez ścisły łeb typu teoretycznego, twórcę Antlr, nie idzie na rozliczne kompromisy architektoniczne , jak projekty od "praktyków".

3

Ty chcesz HTMLe generować.
A jak ten engine (StringTemplate) radzi sobie z XSS?

Bo jak dla mnie jak nie radzi sobie (a nie widzę, żeby coś miał) to w zasadzie jest dyskwalifikacja.

0

Nie będę pisał przed kawą, nie będę pisał przed kawą, nie będę pisał przez kawą.

XSS mi się we łbie zmiksowało z innym zagrożeniem.
Oczywiście że wartości pól się eskejpuje, i "od zarania dziejów" to robię w technologiach, które aktualnie mam w łapie.
Nawet mam zwyczajowe dane testowe na SQL i HTML, podaję nazwisko O'Hara i nazwę firmy Jacek&Wacek, patrzę jakie wyjątki lecą

@jarekr000000:
@Charles_Ray

Taki renderer jest w dystrybucji v4
https://github.com/antlr/stringtemplate4/blob/master/src/org/stringtemplate/v4/StringRenderer.java
należy go związać z typem String

group.registerRenderer(String.class, new StringRenderer());

Jeszcze nie kumam jak pracują specjalizowany formaty, ale rozczaję.

Że libka nie jest zabetonowana w monolitycznej perspektywie projektowej HTML/XML, to nie znaczy że nie posiada ku temu środków, tylko one nie zaburzają czystości "kernela"

0

Lubię obcować z dobrą biblioteką. (Lata temu potrzebowaliśmy technikę wiki w Javie, dominacja na rynku to jebutne monolity nawet z szyciem w JSP, trafiłem na bliki, piękna obiektówka i elastyczność)
*)

Podobne odczucia w ST (jedną z dużych zmian StringTemplate 3 -> 4 jest skrót ST)
Jak sobie przypomnę w innych monolityczną ochronę XSS, zaszytą dla jedynie słusznego formatu HTML ...

        grp = new STGroup('$', '$');   // trzeba wiedzieć, co to group, dolary to separatory do syntaxu templettki
        grp.registerRenderer(Optional.class, new OptionalRenderer());   // nasz
        grp.registerRenderer(String.class, new StringRenderer());   // fabryczny

...

   private class OptionalRenderer implements AttributeRenderer {
        @Override
        public String toString(Object o, String s, Locale locale) {
            Optional<Object> opt = (Optional<Object>) o;
            Object result = opt.isPresent() ? opt.get() : null;

            if (result != null && result.getClass() == String.class) {
                return StringRenderer.escapeHTML((String) result );
            }

            return result.toString();
        }
    }

Rejestracja fabrycznego rederera broni (sprawdzałem !!!), nie broni w Optionalu

    public Optional<String> getCokolwiek() {
        return Optional.of("Janko & Panko </td><td>....");
    }

stąd widoczny w klasie if, bo odpakowanie się odbywa późno w cyklu.
Fajny jest też ErrorListener (silnik daje cztery typy błędów), no ale to w stajni Antlr więc musi być dobrze.

*) BTW jaki nie tylko istniejący, ale dobrze zaprojektowany parser Markdowna polecicie ?

1 użytkowników online, w tym zalogowanych: 0, gości: 1