Saturday, January 11, 2014

Miscellaneous problems with GWT/Spring/Hibernate/Eclipse in web development


Debug breakpoints are not triggered in GWT client package.

Reason: Debug mode form GWT client package only works in the Development mode. In the production mode, the GWT client side runs the compiled Javascript that has lost the information of the debug breakpoints.

Solution: Use the URL of http://127.0.0.1:8888/myproject.html?gwt.codesvr=127.0.0.1:9997 -- note: the "?gwt.codesvr=127.0.0.1:9997" part refers to the code server running the Java version of the client package.


When using GWT SimplePager setPageSize() for the paging of a CellTable, only the first page has data. Pressing the Next button shows no more data and pressing the Back button may raise a null-pointer exception.

Solution: Use a ListDataProvider<T> to inject the data of the list to the widget, e.g.
  CellTable<DataObj> cellTable = new CellTable<DataObj>();
  ...
  cellTable.addColumn(...);
  ...
  cellTable.setRowData(0, dataList);
  cellTable.setRowCount(dataList.size(), true);
  ...
  // Add a pager
  SimplePager.Resources pagerResources = GWT.create(SimplePager.Resources.class);
  SimplePager simplePager = new SimplePager(TextLocation.CENTER, pagerResources, false, 0, true);
  ...
  simplePager.setDisplay(cellTable);
  simplePager.setPageSize(10);
  ...
  // Must use ListDataProvider for correct paging.
  ListDataProvider<DataObj> dataProvider = new ListDataProvider<DataObj>();
  dataProvider.addDataDisplay(cellTable);
  dataProvider.setList(dataList);


org.hibernate.MappingException: Repeated column in mapping for entity: ... column: ... (shold be mapped with insert="false" update="false")

Reason: The column is used as JoinColumn too. If different values are set for the "Column" and "JoinColumn", it will cause inconsistence. Hibernate only allows the changes on one place when doing the insertion or update.

Solution: Use "insertable=false, updatable=false" in all but one mapping, e.g.
  @Column (name="...", insertable=false, updatable="false")
or
  @JoinColumn (name="...", referancedColumnName="...", insertable=false, updatable=false)


Hibernate criteria.list() returns empty list.

Solution: Add
  <property name="packageToScan" value="package.to.scan.for.the.entity.classes" />
to
  <bean id=sessionFactory" 
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">

GWT WindowBuilder cannot find the CSS file. Trying to add new style generates this error message "There are no CSS files referenced from modules HTML."

Reason: The WindowBuilder cannot access the CSS under the "war" directory.

Solution: Create a new subdirectory where the ???.gwt.xml locates. By default, GWT recognizes the directory name as "public". If we want to use another name, such as "css", we need to add
  <public path="css">
into the ???.gwt.xml file. We also add the file name of the CSS file to the ???.gwt.xml file
  <stylesheet src="???.css" />
The GWT compiler will copy all the files under "public" to "war/my-project-name" directory.

Exception from Hibernate 4 when calling sessionFactory.getCurrentSession(): Caused by: org.hibernate.HibernateException: No Session found for current thread.

Solution: Verify that the configuration for transactionManager is correct.  Add @Transactional to the method that calls sessionFactory.getCurrentSession().

Exception from Hibernate: Caused by: org.hibernate.ObjectNoFoundException: No row with the given identifier exists: [...]

Reason: The Entity has a one-to-one, one-to-many etc mapping and the referred Entity has no data for this reference. For example, the User table can be joined to the ContactInfo table. For a user that does not have a record in the ContactInfo table, such an exception will be thrown.

Solution: Use the @NotFound(action=NotFoundAction.IGNORE) annotation for the reference member. The member will then be set as null in the returned Entity.

Associated entities are not saved when saving an entity.

Reason: By default, we have to explicitly save each one.

Solution: Use CascadeType for the mapping, e.g. @OneToOne(cascade=CascadeType.PERSIST), @OneToMany(cascade=CascadeType.ALL), etc. Hibernate will then automatically propagate your action to the associated entity.

Exception: Caused by: org.hibernate.AnnotationException: No identifier specified for entity

Reason: Annotation @Id is missing. Each @Entity needs an @Id. It is the primary key in the database.

To automatically generate column names in uppercase from property name.

Solution: Create a naming strategy from hibernate DefaultNamingStrategy:
  public class MyNamingStrategy extends DefaultNamingStrategy {
    @Override
    public String propertyToColumnName(String propertyName) {
      return proertyName.toUpperCase();
    }
  }
In the configuration XML file, add:
  <property name="namingStrategy">
    <bean class="package.path.to.MyNamingStrategy" />
  </property>

OneToMany unidirectional mapping throws exception: org.hibernate.MappingException: Unable to find column with logical name: ??? in org.hibernate.mapping.Table(???) and its related supertables and secondary tables.

Reason: The elments of "name" and "referencedColumnName" in JoinColumn annotation depend on the context (see http://docs.oracle.com/javaee/6/api/javax/persistence/JoinColumn.html).

Solution: In my case, I need to switch the values of them. And refeencedColumnName should refer to a PHYSICAL column in the source table.

When primary key is used as @OneToOne mapping and @JoinColumn, an exception is thrown: Caused by: java.lang.NullPointerException at org.hibernate.type.descriptor.java.AbstractTypeDescriptor.extractHashCode (AbstractTypeDescriptor.java:88)

Solution: Restructure the code to make sure the target object is persisted first so that the primary key is known when persisting the object in question.

Exception: Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist.

Reason 1: Inconsistency issue. E.g. Class A has a @OnetoMany reference to class B, while class B has a @ManyToOne reference to class A. We need to satisfy both side of the relationship before performing persistence, i.e. objA.getB().add(objB); objB.setA(objA).

Reason 2: Manually set the value for the field of GenerationType.AUTO.

Exception: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role ...... could not initialize proxy - no Session

Solution: use Hibername.initialize() to initialize the proxy before the session is closed.

Exception: com.google.gwt.user.client.rpc.SerializationException: Type 'org.hibernate.collection.internal.PersistentBag' was not included in the set of types which can be serialized by this SerializationPolicy or its Class object could not be loaded. For security purposes, this type will not be serialized.

Solution: http://www.gwtproject.org/articles/using_gwt_with_hibernate.html: 1. write our own light weight DTO, separating from Entity bean. 2. use Dozer to generate DTO for each Entity bean. 3. use Gilead (hibernate4gwt) lib.

Monday, December 23, 2013

Eclipse: create a user library and add JAR files for a project


If there are many common JARs we want to use across several projects, we can create a User Library in Eclipse and add those JARs to it. Later when we are working on a new project which needs those JARs, we can simple add the User Library to the Build Path of the project.

To create a User Library with the JARs added
  1. Click Window on the menu bar and select Preferences.
  2. In the popup dialogue, choose Java->Build Path->User Libraries.
  3. Press the "New..." button, and input the User Library Name in the popup.
  4. Click "Add External JARs" button to add all the JARs we want to the library.
To add our User Library to the project
  1. Right click on the project.
  2. Select "Properties" from the menu.
  3. In the popup dialogue, select Java Build Path.
  4. Click "Add Library ..." button.
  5. Choose User Library from the list.
  6. Check the user library we want to add and click the Finish button.

Thursday, December 12, 2013

Can your data survive system crash? -- MyISAM vs InnoDB with MySQL


The MySQL's website says that: The MySQL updates the files on disk with the write() system call after every SQL statement and before the client is notified about the result.  This means that data file contents are safe even if mysqld crashes, because the operating system ensures that the unflushed data is written to disk. You can force MySQL to flush everything to disk after every SQL statement by starting mysqld with the --flush option.

However, the flush option is off by default. Turning it on can increase the disk I/O operations thus impact the performance. When using the MyISAM engine with the --flush option off, a system crash (such as power cut off or hardware failure) can cause the permanent loss of the unflushed data.

It is a different story with the InnoDB engine. (Quoted:) InnoDB must flush the log to disk at each transaction commit if that transaction made modifications to the database, although you can change the innodb_flush_log_at_trx_commit parameter to other values to change this behavior. Therefore, upon a system crash, InnoDB can recover by replaying the logs. And the beauty is that it is done automatically. (Quoted:) To recover from a crash of your MySQL server, the only requirement is to restart it. InnoDB automatically checks the logs and performs a roll-forward of the database to the present. InnoDB automatically rolls back uncommitted transactions that were present at the time of the crash.
 
Get This <