понедельник, 5 апреля 2010 г.

Java Decompiler

Да, по названию поста будет понятно о чём речь :)
По старой традиции использовал для этих целей всегда JAD. Но он уже достаточно давно заброшен и не справляется с некоторыми фишками. Нашёл хорошую альтернативу, так прям и называется Java Decompiler. Работает как отдельное приложение, так и как плагин к эклипсу.
Больше всего не давали жить две штуки (исходники, которые мне нужны, были просто напичканы ими): ассерты и дженерики. Вот на составил небольшой демонстрационный примерчик:
Исходный текст:

  1. public class Example {  
  2.       
  3.     public class Doing<T extends Some> extends Base<T> {  
  4.         @Override  
  5.         public T doSomething(T param) {  
  6.             assert(param == null);  
  7.             return param;  
  8.         }  
  9.     }  
  10.   
  11.     public abstract class Base<T extends Some> {  
  12.         public abstract T doSomething(T param);  
  13.     }  
  14.   
  15.     public class Some {  
  16.         public Some doing() {  
  17.             return this;  
  18.         }  
  19.     }  
  20.       
  21. }  
То что выдал JAD:
  1. // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.  
  2. // Jad home page: http://www.kpdus.com/jad.html  
  3. // Decompiler options: packimports(3)   
  4. // Source File Name:   Example.java  
  5.   
  6. public class Example {  
  7.     public abstract class Base {  
  8.   
  9.         public abstract Some doSomething(Some some);  
  10.   
  11.         final Example this$0;  
  12.   
  13.         public Base() {  
  14.             this$0 = Example.this;  
  15.             super();  
  16.         }  
  17.     }  
  18.   
  19.     public class Doing extends Base {  
  20.   
  21.         public Some doSomething(Some param) {  
  22.             if (!$assertionsDisabled && param != null)  
  23.                 throw new AssertionError();  
  24.             else  
  25.                 return param;  
  26.         }  
  27.   
  28.         final Example this$0;  
  29.         static final boolean $assertionsDisabled = !Example  
  30.                 .desiredAssertionStatus();  
  31.   
  32.         public Doing() {  
  33.             this$0 = Example.this;  
  34.             super();  
  35.         }  
  36.     }  
  37.   
  38.     public class Some {  
  39.   
  40.         public Some doing() {  
  41.             return this;  
  42.         }  
  43.   
  44.         final Example this$0;  
  45.   
  46.         public Some() {  
  47.             this$0 = Example.this;  
  48.             super();  
  49.         }  
  50.     }  
  51.   
  52.     public Example() {  
  53.     }  
  54. }  
И наш чемпион Java Decompiler:
  1. public class Example {  
  2.     public abstract class Base<T extends Example.Some> {  
  3.         public Base() {  
  4.         }  
  5.   
  6.         public abstract T doSomething(T paramT);  
  7.     }  
  8.   
  9.     public class Doing<T extends Example.Some> extends Example.Base<T> {  
  10.         public Doing() {  
  11.             super(Example.this);  
  12.         }  
  13.   
  14.         public T doSomething(T param) {  
  15.             assert (param == null);  
  16.             return param;  
  17.         }  
  18.     }  
  19.   
  20.     public class Some {  
  21.         public Some() {  
  22.         }  
  23.   
  24.         public Some doing() {  
  25.             return this;  
  26.         }  
  27.     }  
  28. }  
Разница заметна на лицо, комментарии излишни :)

Подсветка кода

Ранее я писал как можно сделать подсветку исходного кода в записях с помощью SyntaxHighlighter. Но пару дней назад официальный сайт отвалился и код перестал подсвечиватся. По сути, если подумать, то делать это в динамике, как это делает SyntaxHighlighter нет смысла. Но на серверную сторону блогера повлиять трудно. Поэтому нашёл замечательный сайт. Идея просто, вставляет код, там используется SyntaxHighlighter от которого получаем статический html, и спокойно вставляем её в запись.

Единственный недостаток, с <, > вообщем запрещёнными символами, которые, например, встречаются в LINQ выражениях. Придётся самостоятельно делать эксейпинг.

Да, и ещё одним преимуществом такого статического подхода, является корректное отображения кода в RSS ридерах и пр. трансляторах, js они не могу проинтерпретировать, а со статичным html'ем справляются на ура.

UPDATE: Не знаю как просмотрел, но есть отличная js библиотечка для динамической подсветки highlight.js от Ивана Сагалаева. Поддерживает целых 35 языков и всё время пополняется, кроме того, у неё есть отличный набор из более чем десятка тем. Я себе под новый дизайн выбрал Dark.

<?xml version="1.0"?>
<response value="ok" xml:lang="en">
  <text>Ok</text>
  <comment html_allowed="true"/>
  <ns1:description><![CDATA[
  CDATA is <not> magical.
  ]]></ns1:description>
  <a></a> <a/>
</response>

понедельник, 22 марта 2010 г.

Ant Magic

Совсем недавно на проекте столкнулись с забавным поведением компиляции из анта. Решил описать, так как по моему это некорректное поведение анта. Вот так выглядит проект:
Код простой. Класс 1 вызывает метод класса 2.
  1. import test.sub2.Sub2;  
  2.   
  3. public class Sub1 {  
  4.    
  5.  public static void sub1() {  
  6.   Sub2.sub2();  
  7.  }  
  8.    
  9. }  
  10.   
  11. package test.sub2;  
  12.   
  13. public class Sub2 {  
  14.  public static void sub2() {  
  15.  }  
  16. }  
Класс Sub2 из другого модуля и не должен компилироваться с основным. Класс 1 тоже не должен компилировать с основным, они оба из модуля 2, но лежат в разных пакетах и пакет Sub1 по случайности не был исключён из компиляции основного модуля 1. Т.о. ант скрипт выглядит вот так:
  1. <project name="TestProject" default="compile">  
  2.   
  3.  <target name="compile">  
  4.   <delete>  
  5.    <fileset dir="bin">  
  6.     <include name="**/*.class"/>  
  7.    </fileset>  
  8.   </delete>  
  9.   <javac srcdir="src" destdir="bin">  
  10.    <exclude name="test/sub2/**" />  
  11.   </javac>  
  12.  </target>  
  13.   
  14. </project>  
Чего я ожидал, что класс Sub2 не будет компилироваться, так как я его исключил и будет ошибка компиляции так как Sub1 пытается импортировать класс, которого нет в classpath.
Но не тут то было, его тоже скомпилирует и всё пройдёт саксес. Хорошо тут специально симулированный простой случай, но начинается полная (_!_) когда Sub2 вызывает ещё какой-то класс, в котором есть специфические методы из библиотек, которых нет в classpath модуля1 и соответственно это умный ант разрулить не может. И человек рвёт на себе волосы, потому что по сути он всё сделал правильно, модуль 2 компилируется без проблем, какого падает компиляция модуля 1, хотя в его классах не было изменений, не понятно. Вообщем вот он какой magic.

суббота, 6 марта 2010 г.

Google Chrome vs (js performance) Opera 10.50

Я в шоке, я негодую! Как можно было заметить по моему блогу я фанат Google Chrome (хотя в целом фанат всей продукции корпорации Добра =D). В качестве основного интернет браузера уже давно только его использую. Но внутренние сервисы на работе иногда открыты по Оперой 10.10. Вот вечером вышел спор/обсуждение с коллегой. За короткий промежуток Opera 10.50 из альфы перешла в релиз. Но речь не об этом. А о том, что горячие норвежские парни переделали javascript движок, добавив модную JIT компиляцию. И знаете что?! Как я ни старался, ни на рабочем компьютере, ни на домашнем, Google Chrome (5.0.342.2 dev) не смог сделать Oper'у в SunSpider тесте! Я просто в шоке:
** TOTAL **:           1.14x as fast     657.2ms +/- 1.7%   576.8ms +/- 2.9%
Немного, но быстрее, и это печалит. Надеюсь потому что у меня Dev версия Хрома. Я уже к Хрому привык, а теперь снова надо думать и это не только потому js быстрее, они снова переделали интерфейс, теперь вкладки очень похожи на Хромовские. И в целом интерфейс стал отзывчивее. Хотя коллега говорит, что есть проблема с отображением и иногда даже паданием некоторых сайтов.
Норвежцы однозначно молодцы!!
UPD:  Производительность «Оперы» 10.50 - странно, а тут немного другие результаты, Хром немного делает оперу.

Результаты ещё пары тестов:

V8 Benchmark Suite - version 5
Google Chrome (5.0.342.2): 3241
Opera 10.50 : 3587

Peacekeeper
Google Chrome (5.0.342.2): 2954 Points
Opera 10.50: 2713 Points

В Peacekeeper всё таки Хром вырвался вперёд, но странно что в собственном V8 тесте не смог.

суббота, 27 февраля 2010 г.

XML - универсальное зло

Хотел написать про набивший оскомину XML. Надоело, что XML используют где только можно в приложениях, мне это не нравиться, этот формат конечно хорош, но надо всё таки проявлять хоть какую-нибудь фантазию.
Мною были замечены три места, где можно более эффективно искоренить XML.

    1. DSL (domain-specific language). Это настолько ужасное место для применение XML, что даже есть книги по тому как это эффективно делать. Моё мнение совпадает со старой статьёй Фаулера: Language Workbenches: The Killer-App for Domain Specific Languages?. Статья уже достаточно старая. Народ, есть же куча генераторов парсеров, которые выдают исходный код на куче всевозможных языков. В качестве рекламы, уже почти полгода как зарелизался продукт от JetBrains: Meta Programming System. Это действительно классная штука. Сам пока баловался только на уровни простых примеров. Но сами JetBrains выпустили отличный баг трекер на нём (сами его используем, язык поисковых запросов у них очень удобный). Я считаю не стоит ленится и сделать свой язык, при этом забыв про XML, и вы посмотрите, у вас получится отличный продукт. Хороший и жизненный пример это aspectj и spring aop. Во втором случае, как всегда в спринге, приходится писать здоровенный xml, а в первом просто немного простых директив непосредственно в коде, при этом отличная интеграция с эклипсом. Показывает например методы, на которые распространяется аспект. По моему даже обсуждать глупо, в этом случае однозначно свой велик.
    2. Разновидность первого, это различные конфигурационные файлы. Скажем так, это более простой случай DSL. Для Java мне кажется достаточно хорошим решением в замен являются аннотации. Очень-очень часто, смена конфигурации несёт переделку кода, так что все равно пересобирать проект. Если динамический язык как Python, то вообще нет вопросов. При использовании средств языка, при создании конфигураций, можно получить много бонусов при использовании IDE, более точный поиск и автоматический рефакторинг. Но, если действительно, нужен текстовый конфиг, который будет часто изменятся, то я считаю лучшее решение это YAML. Чем то напоминает JSON, только более расширенный. Убил бы человека, который придумал, что XML удобный для чтения формат, читать его конечно можно, но это не черта не удобно, столько уже этого насмотрелся во всяких java framework's. Вообщем, если действительно пишете очередной фреймворк, и вам нужны файлы конфигурации, пожалуйста присмотритесь к простым property файлам, может быть вам будет достаточно. Нет? Тогда может YAML, это действительно очень расширяемый и удобный формат, причём всяких парсеров, так же как для XML, для многих языков более чем достаточно.
    3. Обмен данными. Да, вот тут уделать XML не так легко. Рассмотрим два случая:
      1. Формат данных навряд ли будет изменятся. Спросите где это возможно? Например ETL приложение. Одним из ключевых элементов такого приложения является Промежуточное хранилище. В большинстве случаев, внутри такой системы элементы представляют собой словарь атрибутов. Поэтому в качестве промежуточного формата данных можно выбрать бинарный формат [name|value|....]. Причём например если известен максимальный размер имени и значения, при выборке, можно выбирать только нужные поля, пропуская в массиве байтов остальные. 
      2. Будет изменятся. Тут есть проблемы, можно конечно рассмотреть сериализацию объектов, но тогда может возникнуть проблема с десериализацией в разных языках. Можно присмотреться к уже реализованным бинарным протоколам, например Google Protocol Buffers. Конечно, если вам надо распарсить одну XML в час, то вам наверно всеравно, но если пару десятков тысяч в секунду, то приходится задумываться над эффективностью действий. Да и хранение + последующая выборка избыточны и не добавляют производительности приложению. Да, открытось бинарных протоколов оставляет желать лучшего, тогда возвращаемся к упомянутым выше YAML и JSON. Хотя бы для начала посмотрите, как можно решить вашу задачу с их помощью, перед тем как кричать XML.
В целом посыл поста был один. Не стоит использовать XML как универсальное средство решение любой проблемы, потому как есть более эффективные способы решить вашу проблему и стоит вначале оценить их и сравнить с волшебным XML'ем.

Google Chrome и Плагины

Google Chrome классный браузер, полюбил его за скорость и интерфейс. Раньше писал про плагины, которые у него появились. Это круто, что они работают в отдельных процессах, если один падает (что иногда случается так как сижу на dev канале хрома), то просто появляется сообщение и кнопочка перегрузить его. Но есть одна проблема, как только стартует первый процесс браузера, он стартует все плагины, у меня их 6, т.е. стартует ещё 6 процессов. А так как в процессе работы я часто закрываю и открываю его (привык начиная с первой версии хрома), то время первого старта браузера сильно замедлилось, что меня печалит. Поэтому теперь держу gmail открытым как приложение, остальные экземпляры стартуют быстрее. Но вообще да, как-то не очень получается с этими плагинами.
А ещё одно наблюдение, что-то страницы стали грузится не в отдельных процессах иногда, как-то страно это.

четверг, 11 февраля 2010 г.

Java: Read escaped quote as escaped quote from xml

Всё началось с того, что на проекте мы используем написанный нами фреймворк для автоматического тестирования. Многое в нём завязано на xml. В частности очень важная задача сравнение двух xml, "сравнитель" оброс большим количеством всевозможных плюшек. Вот понадобилось ещё одну реализовать. Подробно о ней написала моя коллега: StackoverFlow:Read escaped quote as escaped quote from xml. Ничего дельного ей не ответили до её ухода в отпуск. Задача мне показалась интересной, поэтому решил побаловаться с ней. Вкратце, проблема состоит в том, что когда DOM парсер строит дерево, к значениям элементов применяет unescaping. Нам бы хотелось, чтобы он так не делал, потому что нам надо сравнить два DOM дерева построенных по двум xml файлам, и убедиться именно в их идентичности, что эскейпинг проведен правильно.
На предыдущем проекте пришлось много сражаться с особенностями open source библиотек, которые мы использовали. Причём на форумах тоже было очень молчаливо, а задания делать надо было. Тогда я и заразился любовью в копании в исходниках open source библиотеки, чтобы решить свою проблему, очевидный и очень эффективный метод :)