вторник, апреля 20, 2010

Apache Commons Lang - ToStringBuilder, формирование строки и форматы

Для определённости, возьём такой простой класс:

class Book {
    private String title;
    private String author;
    private Double price;
    private Date   publDate; 
    ... 
}


Я хочу для этого класса получить toString-like отображение.
Удобный для этого способ - взять и применить ToStringBuilder из библиотеки apache commons lang.

Полное имя этого класса -  org.apache.commons.lang.builder.ToStringBuilder.

Способ №1 - руками переопределить метод toString и, с помощью этого класса, описать способ конструирования строкового отображения объектов. Ничего особо примечательного здесь нет, за исключением удобства, которое добавляет упомянутый ToStringBuilder.

    @Override
    public String toString() {
        return new ToStringBuilder(this)
          .append("title", title)
          .append("author", author)
          .append("price", price)
          .append("date", publDate)
          .toString();
      } 


А вот вид получаемой строки зависит от заданного на момент вызова стиля (формата). Примеры этих форматов - чуть низже.

Способ №2 интереснее - он использует reflection. В этом случае мне достаточно вызвать ToStringBuilder.reflectionToString(мой-объект), не занимаясь перечислением имён полей и их значений вручную.

Например, для такого случая

  Book book = new Book();
  book.setAuthor("Gregory M.");
  book.setTitle("The Secret Book of Secrets");
  book.setPrice(15.03);
  book.setPublDate(null); // это специально, чтобы явно показать null-значение


вызов

  System.out.println(ToStringBuilder.reflectionToString(book));

вернёт такой вот результат:
>>> javaapplication243.Book@10b30a7[title=The Secret Book of Secrets,author=Gregory M.,price=15.03,publDate=] 

Да, вот эти >>> я добавил в результат сам, для удобства (моего) при чтении.

Есть несколько способов повлиять на формат получаемого результата.
Результат, показанный чуть выше, получен при использовании формата, используемого по-умолчанию. Имя этого формата - DEFAULT_STYLE.

Можно руками, вызвав статический метод, указать формат, который я хочу использовать:
  
  ToStringBuilder.setDefaultStyle(ToStringStyle.MULTI_LINE_STYLE);

А можно указать нужный формат явным образом, например, вот так:

  ToStringBuilder.reflectionToString(book, ToStringStyle.MULTI_LINE_STYLE)      

Теперь самое интересное - какие форматы есть и как они влияют на результат.

DEFAULT_STYLE
>>> javaapplication243.Book@10b30a7[title=The Secret Book of Secrets,author=Gregory M.,price=15.03,publDate=]  

MULTI_LINE_STYLE
>>> javaapplication243.Book@10b30a7[
      title=The Secret Book of Secrets
      author=Gregory M.
      price=15.03
      date=
    ]


SHORT_PREFIX_STYLE
>>> Book[title=The Secret Book of Secrets,author=Gregory M.,price=15.03,publDate=]

NO_FIELD_NAMES_STYLE
>>> javaapplication243.Book@10b30a7[The Secret Book of Secrets,Gregory M.,15.03,]

SIMPLE_STYLE
>>> The Secret Book of Secrets,Gregory M.,15.03,         

среда, апреля 14, 2010

Составной первичный ключ из двух FK

Встретился несколько необычный случай отображения данных.
На картинке показаны соответствующие таблицы.





В EVENT_KIND содержится список каких-то видов событий, а в VALID_EVENT_KIND - список допустимых сочетаний "предыдущий вид события" - "следующий тип события".

Если работа с EVENT_KIND типична и ничего интересного не представляет, то вот случай с VALID_EVENT_KIND - интереснее.
Классогенератор Netbeans отказыватеся генерировать для этой таблицы соответствующий Entity, резонно, в некотором смысле, сообщая о том, что это ведь обычная таблица связи (для отношения многие-ко-многим), а поэтому и сущность соответствующая не нужна. А раз не нужна, то и делать не буду (упорный, блин).

Другим интересным фактом является использование составного единственного ключа, который состоит из внешних ключей, ссылающихся на одну и ту же таблицу. Такое тоже встречается не часто.

Итак, раз для нас код сгенерировать отказались, остаётся написать его самому. К счастью, особо тут и писать нечего.

Вот так выглядит класс, соответствующий VALID_EVENT_KIND

@Entity
@Table(name="VALID_EVENT_KIND")
public class ValidEventKind implements Serializable {

    @EmbeddedId
    private ValidEventKindPk pk;

    public ValidEventKind() {}

    public ValidEventKind(EventKind prevEvent, EventKind nextEvent) {
        this.pk = new ValidEventKindPk(prevEvent, nextEvent);
    }
}
Ничего интересного, за исключением @EmbeddedId.
А вот и описание самого первичного, embedded-ного, ключа:

@Embeddable
public class ValidEventKindPk implements Serializable {
    @ManyToOne()
    @JoinColumn(name="prev_event", referencedColumnName="code")
    private EventKind prevEventKind;

    @ManyToOne
    @JoinColumn(name="next_event", referencedColumnName="code")
    private EventKind nextEventkind;

    public ValidEventKindPk() { }

    public ValidEventKindPk(EventKind prevEventKind, EventKind nextEventKind) {
        this.prevEventKind = prevEventKind;
        this.nextEventkind = nextEventKind;
    }
}
Разные getters и setters в обоих классах я, очевидное дело, опустил.

Вот и всё...

среда, апреля 07, 2010

Grails - generate-controller и ошибка 404

Создал новое приложение.
Добавил domain-класс Album.
Добавил контроллер, установил ему scaffold.
Всё работает. Приложение запускается, ссылка на контроллер показывается, переход по ссылке переходится.

Теперь я не хочу больше scaffold. Я говорю: а сделай мне generate-controller. Делает.

Запускаю приложение снова. Кликаю по ссылке на контроллер и наблюдаю ошибку:

HTTP Status 404 - /GrailsApplication2/WEB-INF/grails-app/views/album/list.jsp
type Status report
message /GrailsApplication2/WEB-INF/grails-app/views/album/list.jsp
description The requested resource (/GrailsApplication2/WEB-INF/grails-app/views/album/list.jsp) is not available.

Вот этот самый jsp, если честно, меня озадачил.

В итоге определилась причина пробелмы: не были сгенерированы представления (view по-нашему).
Поэтому говорю: generate-views для своего класса - и всё становится ОК.

Netbeans, пусть к JDK

Уже не в первый раз после переустановки JDK соображал, как указать Netbeans на новое её местоположение. Дело в том, что при загрузке он ищет её (или его?) по старому месту, и, не обнаружив, ругается.

Так как каждый раз разбираться заново мне надоело, решил записать.

Путь к JDK указывается в netbeans.conf, который живёт в каталоге INSTALL_DIR/etс:

netbeans_jdkhome="D:\DevTools\Java\jdk1.6.0_19"

Grails - ошибка в синтаксисе команды

Запускаю из коммандной строки grails - получаю сообщение "Ошибка в синтаксисе команды".
Подумал - дистрибутив неправильный может? Нет, нормальный, нетбинзу нравится.

Оказалось: не установлен GRAILS_HOME.

Установил - заработало.