- привести текущие файлы в интересующее нас состояние (в данном случае - восстановить 1.txt из ревизии 4629fbed)
$ git checkout 4629fbedf7d57 1.txt - записать текущее дерево в базу (выведет хеш записанного дерева)
$ git write-tree
82a6654d94d0425c747f1926279a9487bdc95c6a - записать коммит с деревом, записанным в предыдущей ревизии, и парентами: текущая ревизия и ревизия, где файл еще существовал
$ echo "merge" | git commit-tree 82a6654d -p 0301aba7 -p 4629fbed
a75e4109b929b7b0f53b2bc0a8284fcf8569a5e - перейти на новый коммит
$ git reset a75e41
понедельник, 21 ноября 2011 г.
Git. Восстановление удаленных в предыдущих ревизиях файлов или обход Already up-to-date при мерже..
Иногда надо восстановить потертые несколько ревизий назад файлы, сохранив их историю.
Попытка мержить с тем, что находится ниже по дереву ревизий приводит к ошибке Already up-to-date.
Например.
Выполним следующие команды:
Вывод последней команды будет такой (у вас будет отличаться хешами ревизий):
Итак. Допустим, мы вспомнили, что в ревизии 91185e8 зря удалили файл 1.txt и надо его восстановить. Причем, сохранив историю изменений.
Если мы попробуем мерж с ревизией 4629fbed(где файл еще существовал), нам скажут, что уже все смержено:
Выход в использовании более низкоуровневых команд гита. Алгоритм следующий:
пятница, 2 сентября 2011 г.
AspectJ и @NotNull
Контракт надо проверять. И наиболее часто встречающийся контракт метода - ненулевые значения параметров. Обычно проверка выглядит так:
Таким образом на каждый параметр приходится три строчки дополнительного кода. Мало того, что один и тот же код дублируется из метода в метод, так и читаемость ухудшается.
Решение: использовать аспекты и аннотировать нужные параметры @NotNull.
Но что бы не потерять в производительности, надо отказаться от рефлекшина и накладывать условия во время исполнения:
суббота, 6 августа 2011 г.
Решение проблемы testable and encapsulation: Мочим создание объектов..
Исходный код лежит здесь: https://github.com/Fuud/new-instance-transformer (на момент поста ревизия 486d973)
Допустим у нас есть два класса:
Мы хотим протестировать метод CreateInConstructor.getText(). Для этого надо подменить classToMock на затычку-заглушку.
Мне известно два фреймворка, решающих эту проблему: PowerMock и JMockit. Первый не дружит с JMock, а второй представляет отдельную тестовую систему с кучей черной и белой магии. Резюмируя: надо писать что-то свое.
Что нужно:
1) уметь подменять создание нового объекта на получение откуда-то нового. javassist.CodeConvertor.replaceNew()
2) загружать агент при первой необходимости. com.sun.tools.attach.VirtualMachine.loadAgent (это часть attach api)
3) перетрансформировать классы после зарузки агента: Instrumentation.retransformClasses().
После реализации можно делать так:
Допустим у нас есть два класса:
Мы хотим протестировать метод CreateInConstructor.getText(). Для этого надо подменить classToMock на затычку-заглушку.
Мне известно два фреймворка, решающих эту проблему: PowerMock и JMockit. Первый не дружит с JMock, а второй представляет отдельную тестовую систему с кучей черной и белой магии. Резюмируя: надо писать что-то свое.
Что нужно:
1) уметь подменять создание нового объекта на получение откуда-то нового. javassist.CodeConvertor.replaceNew()
2) загружать агент при первой необходимости. com.sun.tools.attach.VirtualMachine.loadAgent (это часть attach api)
3) перетрансформировать классы после зарузки агента: Instrumentation.retransformClasses().
После реализации можно делать так:
пятница, 15 июля 2011 г.
Listeners Support (PropertyChangeSupport с произвольным типом листнеров)
Пусть у нас есть событие:
И слушатель:
Обычно, класс в который можно зарегистрировать слушатель выглядит как-то так:
Два метода fireEvent и fireChange мало того, что выглядят почти одинаково, так еще и имеют кучу таких же клонов в других классах. Повторяющийся код - это плохо. Хочется чего-то вроде этого:
Итог - минус полтора десятка строчек. Добиться этого можно с помощью java.lang.reflect.Proxy (предполагая, что Listener - это интерфейс).
Вот код решения:
И тест к нему:
И слушатель:
Обычно, класс в который можно зарегистрировать слушатель выглядит как-то так:
Два метода fireEvent и fireChange мало того, что выглядят почти одинаково, так еще и имеют кучу таких же клонов в других классах. Повторяющийся код - это плохо. Хочется чего-то вроде этого:
Итог - минус полтора десятка строчек. Добиться этого можно с помощью java.lang.reflect.Proxy (предполагая, что Listener - это интерфейс).
Вот код решения:
И тест к нему:
пятница, 11 марта 2011 г.
Операция с ограниченной частотой вызова.
Иногда надо выполнять некоторую операцию не чаще, чем раз в столько-то времени. Например, если нам надо отображать банковскую котировку. Иногда в секунду прилетает сотня новых значений, иногда - котировка не меняется минутами.
Идея заключается в том, что при вызове операции, помещаем в очередь объект. А в другом потоке ждем, когда объект придет и, если с прошлого вызова до момента получения нового объекта прошло мало времени, спим остаток.
Идея заключается в том, что при вызове операции, помещаем в очередь объект. А в другом потоке ждем, когда объект придет и, если с прошлого вызова до момента получения нового объекта прошло мало времени, спим остаток.
суббота, 19 февраля 2011 г.
Spring: lazy-init.
Рассмотрим вот этот проект.
ChildLazy объявлен как @Lazy, значит он будет загружен по первому требованию (но не раньше).
ChildNormal как @Lazy не объявлен, значит он будет загружен при старте приложения.
Composite так же не @Lazy.
Запустим SpringStart, вывод будет такой:
Видно, что LazyChild загрузился одновременно с NormalChild. Случилось это потому, что Composite, являясь бином-синглетоном, требует LazyChild в качестве своего свойства.
Задачу решает создание ScopedProxy для LazyChild: таким образом в соответствующее свойство Composite будет проставлена только обертка, а сам LazyChild создастся только в том случае, если кто-нибудь вызовет какой-нибудь метод на прокси.
Выглядеть это будет так:
Запустив, получаем:
Из последних трех строчек видно, что задача решена.
ChildLazy объявлен как @Lazy, значит он будет загружен по первому требованию (но не раньше).
ChildNormal как @Lazy не объявлен, значит он будет загружен при старте приложения.
Composite так же не @Lazy.
Запустим SpringStart, вывод будет такой:
created LazyChild created NormalChild Composite is ready Composite.printNormalChild NormalChild.print() Composite.printLazyChild LazyChild.print()
Видно, что LazyChild загрузился одновременно с NormalChild. Случилось это потому, что Composite, являясь бином-синглетоном, требует LazyChild в качестве своего свойства.
Задачу решает создание ScopedProxy для LazyChild: таким образом в соответствующее свойство Composite будет проставлена только обертка, а сам LazyChild создастся только в том случае, если кто-нибудь вызовет какой-нибудь метод на прокси.
Выглядеть это будет так:
Запустив, получаем:
created NormalChild Composite is ready Composite.printNormalChild NormalChild.print() Composite.printLazyChild created LazyChild LazyChild.print()
Из последних трех строчек видно, что задача решена.
вторник, 8 февраля 2011 г.
Компилируем rt.jar c debug информацией.
Задача: добавить debug-информацию в rt.jar.
Шаги решения:
Готовый rt.jar для jdk1.6.0_23 можно скачать тут.
Шаги решения:
- Распаковываем src.zip в c:\_temp\jdk_src\
- Запускаем консоль в папке с распакованными файлами
- Выполняем в консоли "dir /S /B *.java > build.cmd" (без кавычек)
- Открываем build.cmd любимым текстовым редактором
- Заменяем "C:\_temp\jdk_src\" на "javac -g C:\_temp\jdk_src\"
- Запускаем build.cmd
- Долго ждем
- Добавляем с заменой скомпилированные файлы в rt.jar
- Пользуемся
Готовый rt.jar для jdk1.6.0_23 можно скачать тут.
Подписаться на:
Сообщения (Atom)