Showing posts with label functionality. Show all posts
Showing posts with label functionality. Show all posts

Wednesday, 2 September 2009

FreeMarker SimpleHash problem

Обработка шаблонов (Template processing) довольно часто встречается в нынешнее время в разнообразных проектах. Некоторые языки программирования даже совмещают написание логики с "шаблонизатором", что правда зачастую затрудняет поддержку логики. Я же в последнее время пользуюсь открытой библиотекой FreeMarker, которая не привязана к конкретным (особенно веб-ориентированым) технологиям и представляет удобный инструмент и богатый шаблонный язык разметки для Java проектов.

Подробнее о FreeMarker можно узнать по приведенной ссылке, а я сегодня хотел остановиться на некоторой особенности данной библиотеки. Работа с фримаркером начинается с настройки конфигурации, подготовки модели данных и собственно шаблона. Фримаркер - это инструмент отображения вашей модели, потому каждый объект модели оборачивается в специальный класс-обёртку, который не позволяет изменять модель данных из шаблона, а также закрывает доступ к небезопасным методам, которые могут кардинально изменить ход исполнения вашего приложения. Обёртками управляет инстанс ObjectWrapper класса.
Собственно проблема: java.util.Map оборачивается в обёртку, которая оперирует ТОЛЬКО ключами типа String. И если вдруг в Вашей модели попадается что-то вроде java.util.Map<Integer, SomeObject> - ну что ж Вам не повезло... Из данной ситуации есть выход - сменить ObjectWrapper (в поставке от FreeMarker их два) , либо написать свою реализацию, что немного затратно и неудобно. Смена фабрики обёрток ни к чему хорошему не приводит - появляются другие проблемы. Для знакомых с синтаксисом фримаркера:

<#list map?keys as key>
${key}=${map[key]}
<#list>

Начинает возвращать не только ключи мапы, а и названия методов, что очень не удобно для итерирования и естественно выдаёт исключение в ${map[key]}

Выход оказался вполне удобоваримый: исключительно настройками можно добиться нужного поведения:


this.configuration = new Configuration(); this.configuration.setDefaultEncoding("UTF-8");
this.configuration.setURLEscapingCharset("UTF-8"); this.configuration.setBooleanFormat("true,false");
this.configuration.setDateFormat( DateFormatUtils.ISO_DATETIME_FORMAT.getPattern() );
this.configuration.setWhitespaceStripping(true);
this.configuration.setLocalizedLookup(true);
this.configuration.setClassForTemplateLoading(this.getClass(), "/your/package/here");

if ( null != autoincludes )
this.configuration.setAutoIncludes(autoincludes);

BeansWrapper objectWrapper = BeansWrapper.getDefaultInstance();
objectWrapper.setStrict(true);
objectWrapper.setExposeFields(true);
objectWrapper.setSimpleMapWrapper(true);
this.configuration.setObjectWrapper(objectWrapper);


Собственно основное внимание должно быть уделено использованию BeansWrapper и objectWrapper.setSimpleMapWrapper(true);
После этого итерирование по мапе с ключами в виде чисел сводиться к немного изменённому синтаксису (обратите внимание на использование круглых скобок вместо квадратных):

<#list map?keys as key>
${key}=${map(key)}
<#list>

index

Monday, 31 August 2009

Crash functionality

Помните загадку: "У Буратино было 5 яблок. Три яблока он отдал Мальвине. Сколько яблок у Мальвины?", ответом на которую было совсем не три, а моралью: "Инициализируйте переменные господа"?
Сегодня столкнулся с кодом, который инициализировал некоторое целочисленное количество числом 2, а затем уже производились необходимые подсчеты. Надо ли говорить, что не из чистого любопытства я попал на данный участок кода, а из-за плавающей ошибки, которая изредка, но проявлялась. Оказалось всё просто - перед инициализацией нужно вникать в логику действий.
На данном простом примере, я хотел бы показать, что людям свойственно/проще не думать, а выполнять свои обязанности механически. И вправду, зачем вникать в логику вещей, если видно же, что в сумме не хватает еденички? Добавим недостающее при инициализации и забудем о сделанном навсегда. А то, к чему это может привести - это уже забота кого-то другого.

index