Monday, September 3, 2007

Hibernate: Annotation one-to-many( join table)

Unidirectonal one-to-many (join table) association

Hibernate Doc (Chap 8.3.1)


::Relationship::
person(one) -> address(many)

::Java Operation::
person.getAddresses();


::Annotation::


@Entity
@Table(name = "PERSON")
public class Person {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "personId")
  private int id;

  @OneToMany
  @JoinTable(name = "PersonAddress",
    joinColumns = {
      @JoinColumn(name="personId", unique = true)           
    },
    inverseJoinColumns = {
      @JoinColumn(name="addressId")
    }
  )
  private Set<Address> addresses;
}


@Entity
@Table(name = "ADDRESS")
public class Address {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "addressId")
  private int id;
}



::Generated SQL::
- person.getAddresses();
select addresses0_.personId as personId1_, addresses0_.addressId as addressId1_, address1_.addressId as addressId3_0_ from PersonAddress addresses0_ left outer join ADDRESS address1_ on addresses0_.addressId=address1_.addressId where addresses0_.personId=?

[Association Mapping List]

Hibernate: Annotation one-to-many (foreign-key)

Hibernate Doc (Chap 8.2.3)

::Relationship::
person(one) -> address(many)

::DB Schema::
person( personId )
address( addressId, personId )

::Java Operation::
person.getAddresses();

::Annotation::
@Entity
@Table(name="PERSON")
public class Person {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="personId")
private int id;

@OneToMany
@JoinColumn(name="personId") 
private Set <Address> addresses;
}

@Entity
@Table(name = "ADDRESS")
public class Address {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "addressId")
private int id;
}

::Generated SQL (mysql5.0)::
[Association Mapping List]

Monday, July 2, 2007

Java Collection finder methods(spring & ruby style)

Using call-back interface(spring way), I wrote finder methods(block call method in ruby).
I hope this closure-style finding methods provide more human readable sourcecode instead of for-looping.

I've needed to search object(s) in List. In the first place, I repeated for-loops to get objects and check whether it matches criteria. Unfortunately, it was not clean-looking-sorucecode for me.

Unfortunately, only final variables are allowed in callback implementation.

Sample Usage(Junit style)

public class SearcherTest {

private List<Person> people;
private Person p1 = new Person("foo", 1);
private Person p2 = new Person("bar", 2);
private Person p3 = new Person("baz", 3);
private CollectionSearcher<Person> searcher;

@Before
public void setUp() {
people = new ArrayList<Person>();
people.add(p1);
people.add(p2);
people.add(p3);

searcher = new CollectionSearcher<Person>(people);
}


@Test
public void testFind() {
Person result = searcher.find(new SearchStrategy<Person>() {
public boolean isEqual(Person person) {
return person.getName().equals("bar");
}
});

assertSame(p2, result);
}

@Test
public void testFindAll() {
List<Person> result = searcher.findAll(new SearchStrategy<Person>() {
public boolean isEqual(Person person) {
return person.getName().startsWith("b");
}
});

assertEquals(2, result.size());
assertSame(p2, result.get(0));
assertSame(p3, result.get(1));
}

@Test
public void testCollect() {
List<Person> result = searcher.collect(new CollectStrategy<Person>() {
public Person compare(Person person) {
if (person.getId() > 2) {
return person;
}
return null;
}
});

assertEquals(1, result.size());
assertEquals(3, result.get(0).getId());
}

@Test
public void testIndexOf() {
int index = searcher.indexOf(new SearchStrategy<Person>() {
public boolean isEqual(Person person) {
return person.getName().equals("baz");
}
});

assertEquals(2, index);
}

@Test
public void testContains() {
boolean result = searcher.contains(new SearchStrategy<Person>() {
public boolean isEqual(Person person) {
return person.getName().equals("baz");
}
});
assertTrue(result);

result = searcher.contains(new SearchStrategy<Person>() {
public boolean isEqual(Person person) {
return person.getName().equals("foobar");
}
});
assertFalse(result);
}


static class Person {
private String name;
private int id;


public Person(String name, int id) {
this.name = name;
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}
}
}



Implemenatation


public class CollectionSearcher<E> {
private Collection<E> collection;

public CollectionSearcher() {
}

public CollectionSearcher(Collection<E> collection) {
this.collection = collection;
}

/**
* return the first element that given strategy returns true
*
* @param strategy
* @return
*/
public E find(SearchStrategy<E> strategy) {
for (E entry : collection) {
if (strategy.isEqual(entry)) return entry;
}
return null;
}

/**
* returns all element that given strategy returns true
*
* @param strategy
* @return
*/
public List<E> findAll(SearchStrategy<E> strategy) {
List<E> results = new ArrayList<E>();
for (E entry : collection) {
if (strategy.isEqual(entry)) results.add(entry);
}
return results;
}

/**
* return list of elements that strategy returns
* if strategy returns null, then it won't be in the list
*
* @param strategy
* @return
*/
public List<E> collect(CollectStrategy<E> strategy) {
List<E> results = new ArrayList<E>();
for (E entry : collection) {
E result = strategy.compare(entry);
if (result != null) results.add(result);
}
return results;
}

/**
* returns the first index of element that strategy returns true, or -1 if none of the element satisfies the strategy
*
* @param strategy
* @return
*/
public int indexOf(SearchStrategy<E> strategy) {
int index = 0;
for (E entry : collection) {
if (strategy.isEqual(entry)) return index;
index++;
}
return -1;
}

/**
* returns true if the collection has an element that satisfies given strategy
* @param strategy
* @return
*/
public boolean contains(SearchStrategy<E> strategy) {
for (E entry : collection) {
if (strategy.isEqual(entry)) return true;
}
return false;
}


public Collection<E> getCollection() {
return collection;
}

public void setCollection(Collection<E> collection) {
this.collection = collection;
}
}


Search Strategies

public interface CollectStrategy<T> {
T compare(T object);
}

public interface SearchStrategy<T> {
/**
* Returns true if the given object satsfies criteria
* @param object
* @return
*/
boolean isEqual(T object);
}

Thursday, March 22, 2007

Performance: clone() vs. new GregorianCalendar()

Performance for getting a new Calendar Object

::Environment::
- JDK "1.6.0" (build 1.6.0-b105)
- Linux (CentOS 4.4)

::Result::
loopby Clone
by MilliSec
by Setter
by Constructor
100
11ms
11ms
5ms
2ms
1000
59ms
61ms
9ms
6ms
10000
85ms
71ms
59ms
19ms
30000
178ms
136ms
102ms
28ms
60000
279ms
249ms
189ms
42ms



::Code::
By Clone

public long byClone(final int loop) {
final long start = System.currentTimeMillis();
for (int i = 0; i < loop; i++) {
Calendar cal = (Calendar) Calendar.getInstance().clone();
}
final long end = System.currentTimeMillis();
return end - start;
}


By Setting MilliSeconds

public long byMilliSeconds(final int loop) {
final Calendar now = Calendar.getInstance();
final TimeZone tz = now.getTimeZone();
final long mill = now.getTimeInMillis();

final long start = System.currentTimeMillis();
for (int i = 0; i < loop; i++) {
Calendar cal = new GregorianCalendar(tz);
cal.setTimeInMillis(mill);
}
final long end = System.currentTimeMillis();

return end - start;
}


By Setting Each Field

public long bySetter(final int loop) {
final Calendar now = Calendar.getInstance();
final int currentYear = now.get(Calendar.YEAR);
final int currentMonth = now.get(Calendar.MONTH);
final int currentDate = now.get(Calendar.DATE);
final int currentHour = now.get(Calendar.HOUR);
final int currentMinute = now.get(Calendar.MINUTE);
final int currentSecond = now.get(Calendar.SECOND);
final int currentMilliSecond = now.get(Calendar.MILLISECOND);
final TimeZone tz = now.getTimeZone();

final long start = System.currentTimeMillis();
for (int i = 0; i < loop; i++) {
Calendar cal = new GregorianCalendar(tz);
cal.set(currentYear, currentMonth, currentDate, currentHour, currentMinute, currentSecond);
cal.set(Calendar.MILLISECOND, currentMilliSecond);
}
final long end = System.currentTimeMillis();

return end - start;
}


By Constructor

public long byConstructor(final int loop) {
final Calendar now = Calendar.getInstance();
final int currentYear = now.get(Calendar.YEAR);
final int currentMonth = now.get(Calendar.MONTH);
final int currentDate = now.get(Calendar.DATE);
final int currentHour = now.get(Calendar.HOUR);
final int currentMinute = now.get(Calendar.MINUTE);
final int currentSecond = now.get(Calendar.SECOND);
final int currentMilliSecond = now.get(Calendar.MILLISECOND);
final TimeZone tz = now.getTimeZone();

final long start = System.currentTimeMillis();
for (int i = 0; i < loop; i++) {
Calendar cal = new GregorianCalendar(currentYear, currentMonth, currentDate, currentHour, currentMinute, currentSecond);
cal.set(Calendar.MILLISECOND, currentMilliSecond);
cal.setTimeZone(tz);
}
final long end = System.currentTimeMillis();

return end - start;
}

Friday, March 9, 2007

New DI Container from Google

Google released their new Dependency Injection container.
- Google Guice

I found it from Joe Walker's Blog and Bob Lee's blog!!

Nice to have java5 annotation for DI info!!
At my first glimpse, I feel google's developers like to write everything in source code as you see GWT write codes in Java, instead of writing configuration files.

Personally, I agree with their approach.
I haven't had experience that a change only requires modifying configuration files and deploy it without compilation.

My current app uses Spring and configuration files are getting big. Unfortunately I can't say it is clean.(well, there are many ways to deal with it. for example changing loader to read files with our own convention rules)
So, I may feel it's rather convenient writing certain kind of information in source code because we can take advantage of our intelligent IDE.

In Japan, there is yet another famous DI container called Seasar. This is also towarding to less configuration files choosing "Convention Over Configuration" rule.

It's fun to have new DI technologies!!

Thursday, March 8, 2007

Hibernate: Annotation one-to-one (primary-key)

Hibernate Doc (Chap 8.2.2)


::Relationship::
person(one) -> address(one)


::DB Schema::
person( personId )
address( personId )
* address's primary key is same as person's primary key


::Java Operation::
person.getAddress();


::Annotation::
@Entity
@Table(name="PERSON")
public class Person {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="personId")
private int id;

@OneToOne
@PrimaryKeyJoinColumn
private Address address;

public Address getAddress() {
return address;
}
}

@Entity
@Table(name = "ADDRESS")
public class Address {
@Id
@Column(name = "personId")
private int id;
}



::Generated SQL (mysql5.0)::
- person.getAddress();
select person0_.personId as personId2_2_, address1_.personId as personId3_0_, person2_.personId as personId2_1_ from PERSON person0_ left outer join ADDRESS address1_ on person0_.personId=address1_.personId left outer join PERSON person2_ on address1_.personId=person2_.personId where person0_.personId=?

[Association Mapping List]

Hibernate: Annotation one-to-one(foreign-key)

Hibernate Doc (Chap 8.2.2)


::Relationship::
person(one) -> address(one)


::DB Schema::
person( personId, addressId )
address( addressId )


::Java Operation::
person.getAddress();


::Annotation::
@Entity
@Table(name="PERSON")
public class Person {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="personId")
private int id;

@OneToOne
@JoinColumn(name="addressId")
private Address address;
}

@Entity
@Table(name = "ADDRESS")
public class Address {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "addressId")
private int id;
}


[Association Mapping List]