Пусть у нас есть класс User:
Обычно Criteria-api используют в таком стиле:
Мне кажется немного неправильным писать имена свойств в виде строк: могут возникнуть проблемы при рефакторинге.
На решение меня натолкнула библиотека jmock. В результате для getUser(*) получаем такой код:
Осталось реализовать (использую javassist и google-collections):
суббота, 15 января 2011 г.
вторник, 4 января 2011 г.
Hibernate: org.hibernate.MappingException: Unknown entity ...
Если пользуетесь аннотациями для маппинга, и получаете ошибку Unknown entity, проверяйте в первую очередь, что импортируете @javax.persistence.Entity, а не @org.hibernate.annotations.Entity.
среда, 29 декабря 2010 г.
Пара regexp'ов для чистки проекта
Удаление строки author из javadoc:
/\*\*(\n.*$)*?(\n.*author.*$)(\n.*$)*?\n.*\*\/
Удаление пустых многострочных комментов:
\/\*\*\s*(\*\s*)*\*\/
/\*\*(\n.*$)*?(\n.*author.*$)(\n.*$)*?\n.*\*\/
Удаление пустых многострочных комментов:
\/\*\*\s*(\*\s*)*\*\/
вторник, 16 ноября 2010 г.
Spinner с четырьмя кнопками.
Понадобилось сделать спиннер, но с четырьмя кнопками. Две - для изменения значения на единицу и еще две - для изменения на 10.
Рассматривал два решения: поместить в спиннер в качестве эдитора другой спиннер или переписать BasicSpinnerUI (именно оно отвечает за создание и размещение компонентов спиннера). Остановился на втором.
Если наследоваться от BasicSpinnerUI, то получается все довольно просто. В installUI() добавляем на спиннер еще пару кнопок, а в createLayout() возвращаем наш layout, способный правильно расположить на пару кнопок больше.
И вот так можно протестировать:
Рассматривал два решения: поместить в спиннер в качестве эдитора другой спиннер или переписать BasicSpinnerUI (именно оно отвечает за создание и размещение компонентов спиннера). Остановился на втором.
Если наследоваться от BasicSpinnerUI, то получается все довольно просто. В installUI() добавляем на спиннер еще пару кнопок, а в createLayout() возвращаем наш layout, способный правильно расположить на пару кнопок больше.
И вот так можно протестировать:
пятница, 1 октября 2010 г.
Double-check locking.
Идея довольна проста. Пусть у нас есть Singleton, который дорог в создании. Создавать его может потребоваться, а может и нет. Хорошая идея создавать в тот момент, когда он понадобился в первый раз. Получаем код вроде такого:
Обратите внимание на synchonized при декларации метода: каждый раз, когда понадобится ссылка на Singleton, потоку придется захватить монитор, а это весьма дорогостоящая операция.
Если обращение к Singleton'у происходит часто, хотелось бы отказаться от захвата монитора в том случае, если объект уже создан и требуется только чтение.
Неправильное, но интуитивное решение:
Почему же оно неправильное? Причина кроется в специфике Java Memory Model, а именно в том, что обычные (не-volatile) переменные не являются точкой синхронизации.
Пусть у Singletona есть важное для нас поле value:
В худшем случае может происходить следующее:
Все потому, что для не-volatile переменных не гарантируется, что "happens-before order". Нужна некая точка синхронизации. Так как мы хотим отказаться от использования мониторов, то решение: пометить как volatile переменную singleton.
Обратите внимание на synchonized при декларации метода: каждый раз, когда понадобится ссылка на Singleton, потоку придется захватить монитор, а это весьма дорогостоящая операция.
Если обращение к Singleton'у происходит часто, хотелось бы отказаться от захвата монитора в том случае, если объект уже создан и требуется только чтение.
Неправильное, но интуитивное решение:
Почему же оно неправильное? Причина кроется в специфике Java Memory Model, а именно в том, что обычные (не-volatile) переменные не являются точкой синхронизации.
Пусть у Singletona есть важное для нас поле value:
В худшем случае может происходить следующее:
NN | первый поток | второй поток |
---|---|---|
1 | - | getSingleton() |
2 | - | singleton = new Singleton() и value=42 |
3 | - | переменная singleton скидывается в основную память |
4 | getSingleton() | - |
5 | так как переменная singleton не null, в synchronized блок не заходим | |
6 | singleton.value==0 (значение по умолчанию, так как новое значение не было записано еще в основную память) | - |
Все потому, что для не-volatile переменных не гарантируется, что "happens-before order". Нужна некая точка синхронизации. Так как мы хотим отказаться от использования мониторов, то решение: пометить как volatile переменную singleton.
суббота, 18 сентября 2010 г.
Проверка SwingThreadPolicy в рамках всего приложения.
Идея в использовании JavaAgent и инструментаций. Мы добавляем к коду методов проверяемых классов код, проверяющий поток. В данном случае мы инструментируем все наследники java.awt.Component.
Код написан на скале:
Код написан на скале:
пятница, 3 сентября 2010 г.
Написание собственного TableCellEditor на базе JSpinner.
Часто возникает необходимость обеспечить удобный ввод чисел в ячейку таблицы. В виду того, что компонент JSpinner написан, существует в стандартной поставке и работает, хочется использовать именно его.
Здесь полезно знать следующее:
Таким образом, если на editor'e вызвали метод cancelCellEditing, он обязан уведомить всех слушателей об окончании редактирования до выхода из метода (напоминаю, swing однопоточный). То же верно, если он собирается вернуть true из stopCellEditing.
Класс:
И тест к нему (требуется hamcrest 1.2, jmock, junit, fest-swing):
Здесь полезно знать следующее:
- По окончанию редактирования editor обязан вызывать на всех слушателях либо editingStopped либо editingCanceled
- Editor должен закончить редактирование (см. предыдущий пункт), если на нем вызвали метод cancelCellEditing или если он возвращает true на вызов метода stopCellEditing
- Если editor сигнализирует об окончании редактирования вызывая на слушателях editingStopped, это означает, что он готов предоставить новое значение по вызову метода getCellEditorValue
- Если editor сигнализирует об окончании редактирования вызывая на слушателях editingCanceled, это означает, что у него нет нового значения (и в модель ничего нового проставлять не надо)
- Так как таблица удалит своего слушателя сразу после того, как будет просигнализировано об окончании редактирования, можно не бояться вызывать на всех слушателях editingStopped или editingCanceled по несколько раз. Это позволит сделать код более понятным и простым.
Таким образом, если на editor'e вызвали метод cancelCellEditing, он обязан уведомить всех слушателей об окончании редактирования до выхода из метода (напоминаю, swing однопоточный). То же верно, если он собирается вернуть true из stopCellEditing.
Класс:
И тест к нему (требуется hamcrest 1.2, jmock, junit, fest-swing):
Подписаться на:
Сообщения (Atom)