Posted on September 6th, 2008 in EN | No Comments »
JTL, the Java Tools Language (pronounced “Gee-tel”), is a high-level query language for selecting program elements, designed to serve the development of source code software tools for Java.
It is both simple and powerful: you may use it for various source code tasks, from just finding all classes with print() method to executing an extremely complex refactoring transformation.
JTL is very easy to use, its intuitive query-by-example syntax makes it really easy to write JTL queries. For example,
public static double method(int, int);
matches all static methods that receive two int parameters and return a double. And the following query
classWithFactory := is T, class {
no public constructor;
public static T method;
}
matches all factory classes - classes having no public constructor, but instance factory method.
Additional JTL examples may be found in JTL Language Tour. The examples above come from this excellent manual too.
The JTL was initially described in the JTL - The Java Tools Language paper and developed at the Computer Science department at the Technion. But now, after a years of development, JTL goes open source at sourceforge. There is no blog or RSS feed there yet, but I hope those will appear soon.
Posted on July 26th, 2008 in EN | No Comments »
Though claiming a blog at Technorati Profile is not so painful a it looks.
Posted on July 19th, 2008 in EN | 75 Comments »
Also many-to-many associations are usually referenced as a bad design solution, they are widely used in almost all modern database-centric applications (especially in those built around the existing legacy database). The very common scenario is a case when you not only need to handle a many-to-many association but also hold some additional property on the association.
In a J2EE world, Hibernate still remains the most popular ORM tool (or the JPA provider, if you wish). But implementing such a scenario with Hibernate Annotations is not so simple as you might imagine.
First of all, in the good old spirit of the Hibernate community, there is almost no documentation about many-to-many associations and composite keys (two paragraphs stating that there is @ManyToMany and @EmbeddedId annotations are not considered a documentation).
And the second hope of every open-source tool consumer, the world wide web community, provides almost no help: everybody are referencing the same post by Marcel Panse, written in April 2006. Though Marsel’s post is very clean and descriptive, it become outdated and the solution provided there is simply not working with the latest versions of Hibernate Annotations.
So I had to reinvent the wheel by my own, based on Marsel’s sample. Below is the solution working with Hibernate Annotations 3.3.1.GA.
The database part is the same: we have three tables (item, product and product_item), two POJO classes, and two classes for a many-to-many association and its primary key. The main difference from Marsel’s solution is that I’m not using any kind of “fake” properties on ProductItem in order to reference Item and Product, but just a plain transient properties delegating to ProductItemPk.
@Entity
@Table(name = "item")
public class Item {
private Integer id;
private String name;
private List<ProductItem> productItems = new LinkedList<ProductItem>();
public Item() {
}
@Id
@GenericGenerator(name = "generator", strategy = "increment")
@GeneratedValue(generator = "generator")
@Column(name = "item_id", nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "name")
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.item")
public List<ProductItem> getProductItems() {
return this.productItems;
}
public void setProductItems(List<ProductItem> productItems) {
this.productItems = productItems;
}
}
@Entity
@Table(name = "product")
public class Product {
private Integer id;
private String name;
private List<ProductItem> productItems = new LinkedList<ProductItem>();
public Product() {
}
@Id
@GenericGenerator(name = "generator", strategy = "increment")
@GeneratedValue(generator = "generator")
@Column(name = "product_id", nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "name")
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.product")
public List<ProductItem> getProductItems() {
return this.productItems;
}
public void setProductItems(List<ProductItem> productItems) {
this.productItems = productItems;
}
}
Note the two important points: ProductItem has two transient properties for Product and Item (since an unidirectional relationships will be meaningless here) and a use of @AssociationOverrides annotation to specify the database columns
@Entity
@Table(name = "product_item")
@AssociationOverrides({
@AssociationOverride(name = "pk.item", joinColumns = @JoinColumn(name = "item_id")),
@AssociationOverride(name = "pk.product", joinColumns = @JoinColumn(name = "product_id"))
})
public class ProductItem {
private ProductItemPk pk = new ProductItemPk();
@EmbeddedId
private ProductItemPk getPk() {
return pk;
}
private void setPk(ProductItemPk pk) {
this.pk = pk;
}
@Transient
public Item getItem() {
return getPk().getItem();
}
public void setItem(Item item) {
getPk().setItem(item);
}
@Transient
public Product getProduct() {
return getPk().getProduct();
}
public void setProduct(Product product) {
getPk().setProduct(product);
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProductItem that = (ProductItem) o;
if (getPk() != null ? !getPk().equals(that.getPk()) : that.getPk() != null) return false;
return true;
}
public int hashCode() {
return (getPk() != null ? getPk().hashCode() : 0);
}
}
@Embeddable
public class ProductItemPk implements Serializable {
private Item item;
private Product product;
@ManyToOne
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
@ManyToOne
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProductItemPk that = (ProductItemPk) o;
if (item != null ? !item.equals(that.item) : that.item != null) return false;
if (product != null ? !product.equals(that.product) : that.product != null)
return false;
return true;
}
public int hashCode() {
int result;
result = (item != null ? item.hashCode() : 0);
result = 31 * result + (product != null ? product.hashCode() : 0);
return result;
}
}
Hope this helps.
Posted on May 19th, 2008 in RU | No Comments »
После бурного обсуждения на работе выяснилось, что я делаю это не с той стороны, с которой это делают мои коллеги.
Чувствую себя остроконечником.
Posted on April 30th, 2008 in RU | No Comments »
Объявление: “Ищется няня для ребенка 2.8″.
Странно, думаю, а почему фокусное расстояние не указано?
Posted on April 18th, 2008 in RU | No Comments »
Утро, еду на работу. Полупустой вагон, в ушах – наушники, перед глазами – лептоп.
Через несколько сидений от себя замечаю религиозного мужика, накладывающего тфилин.
Всю дорогу каждый занят своим делом: мужик сосредоточено молится, я — читаю статью.
“Уважаемые пассажиры, бла, бла бла”. Ну, приехали наконец-то. Закрываю лептоп, сматываю провод от наушников. Напротив меня мужик абсолютно синхронно со мной закрывает молитвенник и начинает сматывать тфилин. Вытаскиваем сумки, упаковываемся, встаем и продвигаемся на выход.
Бонус: Qumran community: The Phylactery Scroll.
Posted on April 3rd, 2008 in EN | No Comments »
The discussion is probably one of the best examples to the simple rule: programmers should never ever be allowed to lead a product design.
Posted on March 29th, 2008 in RU | 3 Comments »
Для тех кто совсем не в курсе: OpenID — это открытая децентрализованная система единого входа, которая позволяет использовать один логин и пароль на большом количестве сайтов, которую придумал, угадайте кто (нет, не самизнаетекто, а Бред).
Для гиков, фриков и прочих тех, кому не лень: можно настроить у себя на сайте свой собственный OpenID провайдер с помощью phpMyID или PHP Standalone OpenID Server. Желаю успеха. Настроите – приходите, расскажете как было.
А для ленивых вроде меня: проще всего воспользоваться одним из существующих провайдеров и только немного подкрутиь свой сайт. Я настраивал свой блог на WordPress 2.3.3 с помощью провайдера myOpenID
Первое: регистрируем. Заходим на https://www.myopenid.com/ и регистрируемся. В конце регистрации получаем свой собственный OpenID, например http://pupkin.myopenid.com. В принципе, с этим ID уже можно заходить на сайты, комментировать в ЖЖ и в этом блоге и прочая.
Второе: настраиваем. Делаем так, чтбы вместо http://pupkin.myopenid.com можно было писать http://vasya.pupkin.com. Для этого идем на свой сайт http://vasya.pupkin.com и вставляем в таг <head> следующие строчки:
<!-- Start myOpenId settings -->
<link rel="openid.server"
href="http://www.myopenid.com/server" />
<link rel="openid.delegate"
href="http://pupkin.myopenid.com/" />
<link rel="openid2.local_id"
href="http://pupkin.myopenid.com" />
<link rel="openid2.provider"
href="http://www.myopenid.com/server" />
<meta http-equiv="X-XRDS-Location"
content="http://www.myopenid.com/xrds?username=pupkin.myopenid.com" />
<!-- End myOpenId settings -->
И компот третье: проверяем. Идем в ЖЖ, или в комментарии к этой записи, или еще куда (в смысле, где можно заходить в OpenID, а не то, что вы подумали). В поле, которое отмечено значком
пишем http://vasya.pupkin.com и жмем на логин. Вас должно перебросить на страницу myOpenID для логина, а потом обратно, на страницу с комментариями.
Вот и все.
Posted on March 29th, 2008 in RU | No Comments »
В общем, я переехал на http://boris.kirzner.info/blog.
Часть постов будет пока кросспостится в мой ЖЖ (как именно, написано здесь). А вот дневник на VOX я, видимо, закрою. Увы, сколько замечательных скриптов для Greasemonkey не напиши (кстати, за скрипты еще раз большое спасибо dimrub), а все равно – неудобно. А кросспостить и туда и сюда, как мне кажется, глупо (хотя и возможно).
Posted on March 28th, 2008 in RU | 1 Comment »
Куча полезной информации на сайте wiki.noljads.com.
Кросспост из WordPress в ЖЖ.
- Плагин Live+Press (домашняя страница плагина почему-то недоступна).
Я брал пропатченую версию для WordPress 2.0 и выше вот здесь. У меня на WordPress 2.3.3 на заработал
- Плагин LiveJournal Crossposter. Работает замечательно. При желании можно запостить все старые посты из WordPress в ЖЖ.