A data table with grand totals, thanks to Google Charts

8 May 2015, by Baptiste Autin

The Datatable is the core structure of the powerful Google Visualization API. As its name suggests, a Datatable can be used to generate HTML data tables, through a google.visualization.Table object, but it can also be used to generate graphics (along with Google Charts).

Unfortunately, by default, a google.visualization.Table cannot automatically display grand totals, lines or columns, so I will show you how to do that with a bit of script.

Our starting point is just some Javascript objects:

	var data = new google.visualization.DataTable();
	data.addColumn('string', 'Nom');
	data.addColumn('number', 'Janvier');
	data.addColumn('number', 'Février');
	data.addColumn('number', 'Mars');
	data.addColumn('number', 'Avril');
	data.addColumn({type: 'number', label: 'Total'});

	data.addRow(['Jean', 5, 12, 18, 25, 60]);
	data.addRow(['Robert', 0, 1, 20, 2, 23]);
	data.addRow(['Maud', 11, 5, 7, 9, 32]);
	data.addRow(['Tom', 3, 1, 1, 4, 9]);

After a bit of magic on the Datatable data, we create a google.visualization.Table object, we invoke its method draw(), and here is what we get:


Not bad, isn’it?

Read the complete source code here.

Although it is rather easy to get the vertical total (by applying an aggregation google.visualization.data.sum), the horizontal total is more tricky to obtain (you must create x aggregation columns, filter, and add the line).

Note that all columns are sortable, an elegant default feature of the google.visualization.Table

Also note that we had to hack a bit the Total column sort. The last row must be excluded from sorting, indeed, otherwise you’ll see the grand total move up one time in two: hence the listener on the ‘sort’ event, which maintains the grand total at the bottom of the table.

Derived bar charts

As a final present, here are two bar charts, easily obtained from our previously built Datatable, thanks to the Google Charts API.
The first graphic is rendered by instanciating a ColumnChart, and by calling its method draw() with data as parameter:

	var chart = new	google.visualization.ColumnChart(document.getElementById("chart_div"));
	data.removeColumn(data.getNumberOfColumns()-1);		// We must remove the Total column!
	chart.draw(data, options);

To generate the second chart (where columns and rows have swapped), we just need to build an inverted Datatable of data by pivoting.
The code of this permutation can be found in the full source code of the example.

Insert where… not exists

19 January 2015, by Baptiste Autin

Exercise of the day:

Let the TABLE stuff (name VARCHAR(200));
In MySQL dialect, what is the request that inserts the value ‘x’ in the column ‘name’, provided that a row containing that value does not already exist? (otherwise, the request must do nothing)

Reminder: INSERT INTO VALUES ... WHERE ... does not exist in MySQL.


Answer:
INSERT INTO stuff (name) SELECT 'x' FROM DUAL WHERE NOT EXISTS( SELECT 1 FROM stuff WHERE name = 'x');

On the importance of understanding the Spring contexts

31 August 2013, by Baptiste Autin

Lately, I had to work on a buggy application: all the annotations @Transactional, defined at the business level, seemed to be ineffective, in spite of the correct definition of a transactional manager in the main Spring context of the application.

I have to say that the annotated methods were all public (as this is a requirement with @Transactional and JDK proxies)

What the hell was going on?

 

In the file applicationContext.xml (= Web context), I did find the declaration of the JPA manager:

    
    
        
    

As well as the service beans of the application, detected by scan:

                               
       

So I expected the file myapplication-servlet.xml (= Spring MVC context) to define the controllers of the application.
But here is what I stumbled upon:

    

Instead of just scanning the MVC controllers (in foo.myapplication.controllers), we scanned the whole application! Therefore, the business beans were scanned a second time (note that this is not a problem for Spring).
But, like many other things in the Spring framework, the declarative support for transactions relies on AOP proxies, and AOP proxies are only valid in the Spring context where they are defined in. As a consequence, the declaration <tx:annotation-driven />, in the main Spring context, was ineffective in the MVC context.

The solution to my problem simply consisted in bounding the class scan, in myapplication-servlet.xml, to the sole controllers package:

    

Business beans and DAO beans are now defined in the main context, i.e. where the JPA manager is also defined.

 

Conclusion
The MVC Spring context should only contain the components of the MVC framework, and no business- or data-access-logic.
Not respecting this principle is not only a mistake from an architectural perspective, it is prone to erros that may stay hidden long.

Word to HTML conversion with JOD and OpenOffice

30 April 2013, by Baptiste Autin

By combining OpenOffice and the library JODConverter, it is easy to add an Office-to-HTML (or -PDF) document conversion service to a J2EE/Spring application.

Here is the procedure to follow:

1. Install OpenOffice on your server
2. Copy the sample class ConvertorJod (see below) in your webapp, and modify your applicationContext.xml accordingly
3. In ConvertorJod, it is important to modify the path leading to your OpenOffice install, as well as the path of the template profile to use.
4. Start your webapp. A process soffice.bin should appear in your processes list, and your logs should look something like this:

	DEBUG - Starting LibreOffice server...
	org.artofsolving.jodconverter.office.ProcessPoolOfficeManager
	INFO: ProcessManager implementation is PureJavaProcessManager
	org.artofsolving.jodconverter.office.OfficeProcess prepareInstanceProfileDir
	org.artofsolving.jodconverter.office.OfficeProcess start
	INFO: starting process with acceptString 'socket,host=127.0.0.1,port=8100,tcpNoDelay=1' and profileDir (...)
	org.artofsolving.jodconverter.office.OfficeProcess start
	INFO: started process
	org.artofsolving.jodconverter.office.OfficeConnection connect
	INFO: connected: 'socket,host=127.0.0.1,port=8100,tcpNoDelay=1'
	DEBUG [localhost-startStop-1] (ConvertorJod.java:48) [] - LibreOffice server started...

Now that your webapp has correctly started, your document service bean is available to your other beans. As the startup of OpenOffice occurs only once (when the application context mounts), conversion times are rather good (about one or two seconds for an average size file).

Note that if you don’t specify explicitly a template folder, a default one will be used instead, and if that one does not exist, the daemon process soffice.bin will not start.
This is particularly important in the case of a webapp, as it is unlikely that your application server runs under an account for which an Office template folder exists.
You might copy-and-paste the folder of an existing user (with Windows, it is stored under C:\Users\\AppData\Roaming\OpenOffice.org\)
Read/write access must also be set on the folder, otherwise you will get the error:

java.net.ConnectException: connection failed: 'socket,host=127.0.0.1,port=8100,tcpNoDelay=1'; java.net.ConnectException: Connection refused: connect

package test.convertor;

import java.io.File;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.apache.log4j.Logger;
import org.artofsolving.jodconverter.OfficeDocumentConverter;
import org.artofsolving.jodconverter.document.DocumentFormat;
import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration;
import org.artofsolving.jodconverter.office.OfficeConnectionProtocol;
import org.artofsolving.jodconverter.office.OfficeException;
import org.artofsolving.jodconverter.office.OfficeManager;
import org.springframework.stereotype.Service;

@Service
public class ConvertorJod implements AbstractFileConvertor {

	protected final Logger logger = Logger.getLogger(getClass());

	private OfficeManager officeManager = null;
	private OfficeDocumentConverter converter = null;

	@PostConstruct
	protected void initOfficeManager() {
		logger.debug("Starting conversion service...");

		DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration();

		configuration.setPortNumber(8100);
		configuration.setConnectionProtocol(OfficeConnectionProtocol.SOCKET);

		configuration.setTemplateProfileDir(new File("D:\\openoffice\\3"));
		configuration.setOfficeHome(new File("C:\\Program Files (x86)\\OpenOffice.org 3"));

		configuration.setTaskExecutionTimeout(30000L);

		officeManager = configuration.buildOfficeManager();
		converter = new OfficeDocumentConverter(officeManager);

		officeManager.start();

		logger.debug("Conversion service started");
	}

	@PreDestroy
	protected void preDrestroy() {
		logger.debug("Stopping conversion service...");
		officeManager.stop();
		logger.debug("Conversion service stopped");
	}

	@Override
	public void convertToHtml(final File source, final File destination) throws OfficeException {

		DocumentFormat outputFormat = converter.getFormatRegistry().getFormatByExtension("html");    // "html" ou "pdf"

		logger.debug("Converting " + source.getName());

		converter.convert(source, destination, outputFormat);
	}
}

And here is the Java interface of the service (inject it in every business bean that needs HTML conversion):

package test.convertor;

import java.io.File;

import org.artofsolving.jodconverter.office.OfficeException;

public interface AbstractFileConvertor {

	void convertToHtml(File source, File destination) throws OfficeException;

}

Returning WS-attachments with Spring Web Service 1.5.9

30 July 2012, by Baptiste Autin

Since Spring WS version 2.0, it is straightforward to get a MessageContext object from within the endpoints, and therefore to retrieve/return attachments from/in SOAP messages.

But with the previous release (1.5.9), the one I still have to use at work, it is not that simple.
So I started from an idea given by another Java blogger, explained here, which consists in intercepting the SOAP request, and saving the MessageContext in a ThreadLocal.
In his post, the author of that trick shows how to extract an attachment sent by the client to the web service.
I am going to show you the opposite way: how to add an attachment in the web service response.

@Endpoint
@Transactional
public class MySoapServerImpl implements MySoapServer {

    @Autowired
    private SaajSoapMessageFactory saajMessageFactory;
    
    @Autowired
    private ApplicationContext ctx;
    
    @Override
    @PayloadRoot(namespace = "some namespace", localPart = "FindSomethingRequest")
    public FindSomethingResponse FindSomething(FindSomethingRequest request) throws InvalidParameterException, IOException {
        
        final FindSomethingResponse response = new FindSomethingResponse();
        
        WebServiceMessage message = saajMessageFactory.createWebServiceMessage();
        SoapMessage soapMessage = (SoapMessage) message;
        
        File file = ctx.getResource("foo.jpg").getFile();    // here is the file we want to send back
                    
        soapMessage.addAttachment(file.getName(), file);
        
        MessageContextHolder.getMessageContext().setResponse(soapMessage);
    
        return response;
    }
}

And as a reminder, this is how to intercept and save a SOAP message in a ThreadLocal:



    
    
        
            
        
    

@Component("MsgCtxInterceptorAdapter")
public class MsgCtxInterceptorAdapter extends EndpointInterceptorAdapter {
       
    @Override
    public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {

        MessageContextHolder.setMessageContext(messageContext);
        //messageContext.getRequest().writeTo(System.out);
        return super.handleRequest(messageContext, endpoint);
    }
   
    @Override
    public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
       
        MessageContextHolder.removeMessageContext();
        //messageContext.getResponse().writeTo(System.out);
        return super.handleResponse(messageContext, endpoint);
    }
   
    public boolean handleFault(MessageContext messageContext, Object endpoint) {
       
        MessageContextHolder.removeMessageContext();
        return super.handleFault(messageContext, endpoint);
    }
}
public final class MessageContextHolder {
    private static ThreadLocal<MessageContext> threadLocal = new ThreadLocal<MessageContext>() {
        @Override
        protected MessageContext initialValue() {
            return null;
        }
    };

    private MessageContextHolder() {
    }

    public static MessageContext getMessageContext() {
        return threadLocal.get();
    }

    public static void setMessageContext(MessageContext context) {
        threadLocal.set(context);
    }

    public static void removeMessageContext() {
        threadLocal.remove();
    }
}

Spring Batch: persisting data in the Step Execution Context

3 April 2012, by Baptiste Autin

In the method execute() of a Tasklet, if you want to store data in the ExecutionContext of the current Step, be careful.
Don’t write:

chunkContext.getStepContext().getStepExecutionContext().put("myKey", "myValue");

Instead write:

chunkContext.getStepContext().getStepExecution().getExecutionContext().put("mode", "test");

Indeed, getStepExecutionContext() returns a unmodifiable collection. So you are good for a java.lang.UnsupportedOperationException at java.util.Collections$UnmodifiableMap.put(Collections.java:1285)
if you try to modify what it returns.



Note: if you use an ItemWriter instead of a Tasklet, you can’t go wrong, as you have to explicitly add a listener with a @BeforeStep:

private StepExecution stepExecution;

@BeforeStep
public void saveStepExecution(StepExecution stepExecution) {
    this.stepExecution = stepExecution;
}

(...)

this.stepExecution.getExecutionContext().put("someKey", "myValue");

Mixing inheritance strategies in Hibernate

27 September 2011, by Baptiste Autin

Inheritance does not exist in the entity-relationship model as such.
In a relational database, one can represent inheritance relationship:

  • Either with two tables and an intermediary association (joined strategy in JPA)
  • Either with a single table in which the two entities have merged, along with an additional column to discriminate the name of the entity (single_table strategy)

A variant of the latter strategy also exists (table per class), but I ignore it for simplicity (it consists in defining one table per concrete class, gathering the attributes of the concrete class as well as those of all the superclasses).

Both of these strategies has advantages and disadvantages in terms of performance, ease of use, scalability, compliance / non-compliance with normal forms…

Hibernate supports both techniques, and can even mix them.
It is that mixing inheritance strategy that I am going to talk to you now.

Use case

I have taken my inspiration from this article, a bioinformatics paper that proposes an ontology of clinical terms associated with neoplasms.
I will not dwell on ontologies, nor on tumors ; I am just taking the classification scheme provided by the author as an example.

From this scheme, I have extracted the following class diagram:

Let’s assume now that these classes have some attributes and methods (not listed).

Let’s also assume that the top class (Neoplasm) and the middle classes (NeuralCrest, GermCell, Mesoderm, Trophectoderm, Neuroectoderm and EndodermEctoderm) are abstract.
And the other ones are concrete.

Now imagine that we want to persist instances of concrete classes in a relational database.
How are we going to proceed?
And first, how are we going to map this object model to a physical database model?

To start, it is likely that some of these classes will share common attributes (a latin name, a family, a biological category, a set of associated vocabularies, etc.)
Contrarily, the bottom-level classes will probably have specific very attributes.
For instance:

Creating one big single table “neoplasm” including all attributes of all classes, along with an additional field to discriminate the class name, is not very elegant… even if that solution is probably a winner in terms of performance (no table joins needed). I am saying “probably” because it depends on how the database will handle a large number of columns with NULL values. Moreover, indexing a column of that big table means indexing all the recordings of that table… including, potentially, unnecessary ones.

Creating one table per concrete class, with as many foreign keys as there are inheritance relationships, is a classic solution… But with 26 classes, we need 26 tables.
Moreover, if bottom classes have few attributes of their own, is it really necessary to create dedicated tables only for them?
Couldn’t we limit the number of tables by combining some tables, locally?

That’s where mixing inheritance strategies comes in handy.

I suggest the following:
– Each top and middle class will be mapped to a dedicated table
– Bottom classes will be merged in the middle class they inherit

For example, classes Molar and Tropoblast will be grouped in the table Tropectoderm, classes NeuroectodermPrimitive and NeuralTube in the table Neuroectoderm, etc.

The table definition for Trophectoderm then becomes: trophectoderm (id, a, b, c, d, e, f, type)
Field type is the type discriminator of the class hierarchy (we need one, since we have merged some classes). By default, Hibernate automatically populates this field with the simple name of the Java classes.

Mapping

We set a “single table” strategy on the class Neoplasm :

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)

Every second level class declares a secondary table :

@SecondaryTable(name="NeuralCrest", pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))

Third level classes use both the secondary table AND the global table (Neoplasm).

Note that JPA annotations are not automatically inherited, and therefore must explicitly be set in all the subclasses.
Also note that it is necessary to redefine the table name in all the @Column annotations that refer to a secondary table:

@Column (table = TABLE_NAME)
private String s;

That’s why my code makes use of a public constant TABLE_NAME, in order to define in one single place the name of the mapped table.

Care should be taken to create a referential integrity constraint on the primary key of each table towards the primary key of Neoplasm (ie Trophectoderm.id -> Neoplasm.id, NeuralCrest.id -> Neoplasm.id, etc..). This will prevent deleting from a secondary table without deleting the associated row in Neoplasm.

Using the API

We can now make persistent our objects. For example:

NeuralCrestPrimitive NeuralCrestPrimitive ncp = new ();
ncp.setLatinName ("Pia mater");
ncp.setA ("Example # 1");
ncp.setB ("Example # 2");
session.persist (ncp);

Hibernate then executes the following two commands:
insert into neoplasm (latinName, type) values ??('Pia Mater', 'NeuralCrestPrimitive')
insert into neural_crest (a, b, id) values ??(Example # 1 Example # 2 [last inserted id])

Conclusion
We mapped our object model to a database model containing 7 tables, instead of 26 tables with the usual joined strategy.
A read operation in a bottom table requires only one table join, a write operation two inserts (or updates).
It is a compromise solution, which is particularly interesting:
– When the height of the hierarchical tree is large (at least 3 levels)
– When the bottom classes structuraly differs little from one class to another within the same branch
– When the class structure is very different from one branch to another

Java classes

// *********
// Top class
// *********

@Entity
@Table(name = Neoplasm.TABLE_NAME)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
abstract public class Neoplasm {

	public static final String TABLE_NAME = "neoplasm";

	@Id @GeneratedValue
	private int id;
	
	@Column(name = "latinName")
	private String latinName;
	
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getLatinName() {
		return latinName;
	}
	public void setLatinName(String latinName) {
		this.latinName = latinName;
	}
}

// **************
// Middle classes
// **************

@Entity
@SecondaryTable(name=NeuralCrest.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
abstract public class NeuralCrest extends Neoplasm {
	
	public static final String TABLE_NAME = "neural_crest";
	
	@Column(table=TABLE_NAME)
	private String a;
	
	@Column(table=TABLE_NAME)
	private String b;
	
	public String getA() {
		return a;
	}
	public void setA(String a) {
		this.a = a;
	}
	public String getB() {
		return b;
	}
	public void setB(String b) {
		this.b = b;
	}
}

@Entity
@SecondaryTable(name = GermCell.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
abstract public class GermCell extends Neoplasm {
	
	public static final String TABLE_NAME = "germ_cell";
}

@Entity
@SecondaryTable(name = Mesoderm.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
abstract public class Mesoderm extends Neoplasm {
	
	public static final String TABLE_NAME = "mesoderm";
}

@Entity
@SecondaryTable(name = Neuroectoderm.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
abstract public class Neuroectoderm extends Neoplasm {
	
	public static final String TABLE_NAME = "neuroectoderm";
}

@Entity
@SecondaryTable(name = EndodermEctoderm.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
abstract public class EndodermEctoderm extends Neoplasm {
	
	public static final String TABLE_NAME = "endoderm_ectoderm";
}

@Entity
@SecondaryTable(name = Trophectoderm.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
abstract public class Trophectoderm extends Neoplasm {
	
	public static final String TABLE_NAME = "trophectoderm";
}

// **************
// Bottom classes
// **************

@Entity
@SecondaryTable(name = NeuralCrest.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class Ectomesenchymal extends NeuralCrest {
	
	@Column(table=TABLE_NAME)
	private String d;
	
	public void setD(String d) {
		this.d = d;
	}

	public String getD() {
		return d;
	}
}

@Entity
@SecondaryTable(name = NeuralCrest.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class NeuralCrestEndocrine extends NeuralCrest {
	
	@Column(table=TABLE_NAME)
	private String d;
	
	@Column(table=TABLE_NAME)
	private String e;

	public void setD(String d) {
		this.d = d;
	}
	public String getD() {
		return d;
	}
	public void setE(String e) {
		this.e = e;
	}
	public String getE() {
		return e;
	}
}

@Entity
@SecondaryTable(name = NeuralCrest.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class NeuralCrestPrimitive extends NeuralCrest {
		
	@Column(table = TABLE_NAME)
	private String d;

	public void setD(String d) {
		this.d = d;
	}

	public String getD() {
		return d;
	}
}

@Entity
@SecondaryTable(name = NeuralCrest.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class PeripheralNervousSystem extends NeuralCrest {
	
	@Column(table=TABLE_NAME)
	private String c;
	
	@Column(table=TABLE_NAME)
	private String f;
	
	@Column(table=TABLE_NAME)
	private String g;
	
	public String getC() {
		return c;
	}
	public void setC(String c) {
		this.c = c;
	}
	public String getF() {
		return f;
	}
	public void setF(String f) {
		this.f = f;
	}
	public String getG() {
		return g;
	}
	public void setG(String g) {
		this.g = g;
	}
}


@Entity
@SecondaryTable(name = Mesoderm.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class Coelomic extends Mesoderm {
}

@Entity
@SecondaryTable(name = GermCell.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class Differentiated extends GermCell {
}

@Entity
@SecondaryTable(name = EndodermEctoderm.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class EndodermEctodermEndocrine extends EndodermEctoderm {
}

@Entity
@SecondaryTable(name = EndodermEctoderm.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class EndodermEctodermPrimitive extends EndodermEctoderm {
}

@Entity
@SecondaryTable(name = Mesoderm.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class Mesenchymal extends Mesoderm {
}

@Entity
@SecondaryTable(name = Mesoderm.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class MesodermPrimitive extends Mesoderm {
}

@Entity
@SecondaryTable(name = Trophectoderm.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class Molar extends Trophectoderm {
}


@Entity
@SecondaryTable(name = Neuroectoderm.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class NeuralTube extends Neuroectoderm {
}

@Entity
@SecondaryTable(name = Neuroectoderm.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class NeuroectodermPrimitive extends Neuroectoderm {
}

@Entity
@SecondaryTable(name = EndodermEctoderm.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class Odontogenic extends EndodermEctoderm {
}

@Entity
@SecondaryTable(name = EndodermEctoderm.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class Parenchymal extends EndodermEctoderm {
}

@Entity
@SecondaryTable(name = GermCell.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class Primordial extends GermCell {
}

@Entity
@SecondaryTable(name = Mesoderm.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class Subelomic extends Mesoderm {
}

@Entity
@SecondaryTable(name = EndodermEctoderm.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class Surface extends EndodermEctoderm {
}

@Entity
@SecondaryTable(name = Trophectoderm.TABLE_NAME, pkJoinColumns = @PrimaryKeyJoinColumn(name="id"))
public class Trophoblast extends Trophectoderm {
}

Variant
Rather than letting Hibernate save textually the class name in the discriminator column, we could define an entity NeoplasmType(id, name), and set a foreign key in Neoplasm for this entity.
We then must not forget to define the corresponding numerical identifier in every concrete class, with the annotation @DiscriminatorValue.

For example, the mapping of the class Trophectoderm becomes:

@Entity
@SecondaryTable(name="trophectoderm", pkJoinColumns=@PrimaryKeyJoinColumn(name="id"))
@DiscriminatorValue("3")	// si "3" est l'identifiant numérique correspondant à "Trophectoderm" dans la table NeoplasmType 
abstract class Trophectoderm extends Neoplasm {
	(...)
}

We must also specify in Neoplasm that Hibernate should not rely on the class name to discriminate the entity class, but on a numeric identifier and a table join:

@Entity
@Table(name = Neoplasm.TABLE_NAME)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "id_type", discriminatorType = DiscriminatorType.INTEGER)
abstract public class Neoplasm {
	(...)
	@ManyToOne
	@JoinColumn(name="id_type", nullable=false, insertable=false, updatable=false)
	private NeoplasmType type;
	(...)
}

EasyMock et Autowiring

27 July 2011, by Baptiste Autin

Spring Test, JUnit and EasyMock are a good team for unit testing.
Unfortunately, classes that inject their properties by autowiring can be difficult to test when these properties have to be mocked (DAO for example).

Normally, with Spring, you inject your mocks thanks to the attribute factory-method :

<bean class="org.easymock.EasyMock" factory-method="createMock" id="ClientDAO">
	<constructor-arg value="com.example.dao.IClientDAO" />
</bean>

Now, let’s say that the class to be tested injects its DAO like this:

@Autowired
protected IClientDAO cDao;

The context startup is then likely to fail:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.example.dao.IClientDAO] is defined: Unsatisfied dependency of type [interface com.example.dao.IClientDAO]: expected at least 1 matching bean

Why? Because Spring determines the type of a factory-method-defined bean by reflection. So if the method returns an Object or a parameterized type, just like EasyMock.createMock() does, autowiring by type will not work (even if you specify the bean’s name with @Qualifier).

Solutions :

  • Utiliser l’annotation @Resource
    @Resource(name="ClientDAO")
    protected IClientDAO cDao;

    But you may not want to use that annotation, or make an explicit reference to the name of a bean.

  • Use an adapter class, that will explicitely specify the good return type (here, IClientDAO) :
    public class MocksFactory {
    
    	public IClientDAO getClientDAO() {
    		return EasyMock.createMock(IClientDAO.class);
    	}
    }

    Unfortunately, you will have to write as many methods as there are objects to mock, which might be tedious.

    If you are not satisfied with any of these two solutions, there is a last possibilty: defining an unmocked version of your class (so that autowiring can work), and then relying on the interface BeanFactoryPostProcessor to replace this unmocked bean, in Spring’s registry, by a mocked version.
    Just two classes are required for that:
    – a class MocksFactory to generate the mocked object (thanks to FactoryBean)
    – a class MocksFactoryPostProcessor which will receive a list of beans names to redefine.

import org.easymock.classextension.EasyMock;
import org.springframework.beans.factory.FactoryBean;

public class MocksFactory implements FactoryBean {

	private Class type;

	public void setType(final Class type) {
		this.type = type;
	}

	@Override
	public Object getObject() throws Exception {
		return EasyMock.createMock(type);
	}

	@Override
	public Class getObjectType() {
		return type;
	}

	@Override
	public boolean isSingleton() {
		return true;
	}
}
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;

public class MocksFactoryPostProcessor implements BeanFactoryPostProcessor {

	private static final Class factoryClass = MocksFactory.class;
	
	private String[] beanNames;

	@Override
	public void postProcessBeanFactory(final ConfigurableListableBeanFactory context) throws BeansException {
		
		BeanDefinitionRegistry registry = (BeanDefinitionRegistry) context;
		
		for (String beanName : beanNames) {
			
			BeanDefinition bd = registry.getBeanDefinition(beanName);
											
			MutablePropertyValues values = new MutablePropertyValues();
			values.addPropertyValue(new PropertyValue("type", bd.getBeanClassName()));
			
			RootBeanDefinition definition = new RootBeanDefinition(factoryClass, values);
			registry.registerBeanDefinition(beanName, definition);
		}
	}
	
	public void setBeanNames(String[] beans) {
		this.beanNames = beans;
	}
}

Finally, in the applicationContext.xml, the comma-separated list of beans names is set through the property beanNames :

<bean id="ClientDAO" class="com.example.dao.ClientDAO"/>
<bean id="mocksFactoryPostProcessor" class="com.example.MocksFactoryPostProcessor">
	<property name="beanNames" value="ClientDAO,ProductDAO,ContractDAO"/>
</bean>

Note that this solution requires that you make use of classextension.EasyMock (to mock by concrete class, and not by interface).

Remarque : instead of defining all the bean names, like we are doing, we could browse Spring’s registry and redefine all those that are injected with @Autowired

Date conversion with Castor XML

4 April 2010, by Baptiste Autin

Castor is a lightweight and efficient Java / XML data binding tool.
One of the first pitfalls you can fall into is conversion date.
Castor provides a mechanism to customize serialize / deserialize fields via a handler class. The most practical solution I’ve experienced is to extend the class GeneralizedFieldHandler, as in the example below.

Here is our Java bean instance:

package articles;

import java.util.Date;

public class Version {

	private String name;
	private Date releaseDate;

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Date getReleaseDate() {
		return releaseDate;
	}
	public void setReleaseDate(Date date) {
		this.releaseDate = date;
	}
}

The Castor mapping file /articles/mapping.xml:

<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN" "http://castor.org/mapping.dtd">
<mapping>
	<description></description>
	<class name="articles.Version">
		<map-to xml="version" />
		<field name="releaseDate" type="string" handler="articles.DateHandler">
			<bind-xml name="releaseDate" />
		</field>
		<field name="name" type="string">
			<bind-xml name="name" />
		</field>
	</class>
</mapping>

The sample XML file (for unmarshalling) /articles/history.xml:

<?xml version="1.0" standalone="yes"?>
<versions>
	<version>
		<name>JDK 1.1.4</name>
		<releaseDate>12-09-1997</releaseDate>
	</version>
	<version>
		<name>JDK 1.1.5</name>
		<releaseDate>03-12-1997</releaseDate>
	</version>
	<version>
		<name>JDK 1.1.6</name>
		<releaseDate>typo</releaseDate>
	</version>
</versions>

The handler class:

package articles; 

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.exolab.castor.mapping.GeneralizedFieldHandler;

public class DateHandler extends GeneralizedFieldHandler {

	private static final Log logger = LogFactory.getLog(DateHandler.class);

	private static final String FORMAT = "dd-MM-yyyy";

	private SimpleDateFormat formatter = new SimpleDateFormat(FORMAT);

	public Object convertUponGet(Object value) {
		if (value == null) {
			return "13-07-1974";	// default value if null date
		}
		Date date = (Date) value;
		return formatter.format(date);
	}

	public Object convertUponSet(Object value) {
		Date date = null;
		try {
			date = formatter.parse((String) value);
		}
		catch (ParseException px) {
			logger.error("Parse Exception (bad date format) : " + (String) value);
			return null;  // default value for empty/incorrect date
		}
		return date;
	}

	public Class<?> getFieldType() {
		return Date.class;
	}

	public Object newInstance(Object parent) throws IllegalStateException {
		return null;
	}
}

And finally the executable:

package articles;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Date;

import org.apache.log4j.Logger;
import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.mapping.MappingException;
import org.exolab.castor.xml.MarshalException;
import org.exolab.castor.xml.Marshaller;
import org.exolab.castor.xml.Unmarshaller;
import org.exolab.castor.xml.ValidationException;
import org.xml.sax.InputSource;

public class CastorTest {

	private static Logger logger = Logger.getLogger(CastorTest.class);
	private static Mapping mapping = getMapping();

	final private static String MAPPING_FILE = "/articles/mapping.xml";

	public static void main(String[] args) throws MappingException, MarshalException, ValidationException, IOException {

		/**
		 * Unmarshalling (XML -> Java)
		 */

		Unmarshaller unmarshaller = new Unmarshaller(ArrayList.class);
		unmarshaller.setIgnoreExtraElements(true);
		unmarshaller.setMapping(mapping);

		String dataFile = CastorTest.class.getResource("/articles/history.xml").getPath();
		InputSource source = new InputSource(dataFile);
		ArrayList<Version> list = (ArrayList<Version>) unmarshaller.unmarshal(source);

		logger.debug("Unmarshalling :");
		for (Version item : list) {
			logger.debug("Name = " + item.getName());
			logger.debug("Date = " + item.getReleaseDate());
		}

		/**
		 * Marshalling (Java -> XML)
		 */

		Marshaller marshaller = new Marshaller();
		Writer writer = new StringWriter();

		marshaller.setWriter(writer);
		marshaller.setMapping(mapping);

		Version v = new Version();
		v.setName("New name");
		v.setReleaseDate(new Date());

		marshaller.marshal(v);

		logger.debug("Marshalling :");
		logger.debug(writer.toString());
	}

	static protected Mapping getMapping() {

		String mapFile = CastorTest.class.getResource(MAPPING_FILE).getPath();
		InputSource is = new InputSource(mapFile);

		Mapping mapping = new Mapping();
		mapping.loadMapping(is);

		return mapping;
	}
}

Expected traces at runtime :

DEBUG [main] (CastorTest.java:39) [] - Unmarshalling :
DEBUG [main] (CastorTest.java:41) [] - Name = JDK 1.1.4
DEBUG [main] (CastorTest.java:42) [] - Date = Fri Sep 12 00:00:00 CEST 1997
DEBUG [main] (CastorTest.java:41) [] - Name = JDK 1.1.5
DEBUG [main] (CastorTest.java:42) [] - Date = Wed Dec 03 00:00:00 CET 1997
DEBUG [main] (CastorTest.java:41) [] - Name = JDK 1.1.6
DEBUG [main] (CastorTest.java:42) [] - Date = null
(...)
DEBUG [main] (CastorTest.java:61) [] - Marshalling :
DEBUG [main] (CastorTest.java:62) [] - <?xml version="1.0" encoding="UTF-8"?>
<version><releaseDate>04-04-2011</releaseDate><name>New name</name></version>

Note how the deliberately erroneous date in the third <version> of the list has been handled, and how we get a null instead, as expected.
The advantage of extending GeneralizedFieldHandler, as we do, is that DateHandler can be reused for other date fields. However, if different date formats were expected, we would have to implement ConfigurableFieldHandler.

More information:
http://www.castor.org/xml-fieldhandlers.html

My Work Study

23 March 2009, by Baptiste Autin

On 14 November 2008, I defended my degree work in computer science at the CNAM high school of Paris, thus completing five years of studies taken in addition to my job.

My studies at the CNAM are marked by diversity.
They began with a first set of courses called “Driving System” (systems architecture, system programming (C under Linux), software engineering, distributed applications, networks).

My major was database engineering: relationnal/multimedia/spatial databases, indexing, documents searching, as well as the XML standards.

I also wrote a report about metaheuristics (which are particular iterative techniques to optimize combinatorial problems).

My final report focused on my work at the Institut Curie for 18 months, where I developed a distributed software to integrate biomedical, statistical and genomic data.

These courses at the CNAM, added to my initial training as an analyst-programmer (see my CV) allow me to deal with many problems arising in IT.

« Older Entries