Groovy Integration in JEE Application

It’s not possible to harness one cart
Horse and quivering doe
                        A.S. Pushkin

Hello!

In this post, I want to talk about how to integrate Groovy into an existing Maven-based JEE application. Thanks to Anton Schastny schaan for permission to use the source code of his project as a starting point. Therefore, this topic can be considered a continuation of his article Learning to cook: Spring 3 MVC + Spring Security + Hibernate .

Let's get started.

Project preparation.

I am using Eclipse in the SpringSource Tool Suite assembly. Deflate the ContactManager project . But do not rush to open it in the IDE. It will be even more reliable if you delete all project files at all: .classpath .project and the .settings directory. For since the publication of the article by Anton, technology has stepped forward, new versions of STS have been released (with a different project structure and a new version of the m2e plugin), so we will first fix the pom-file, then STS will create a new project based on it.

For simplicity, I removed aspect dependencies and Spring Roo from pom.xml. Also replaced MySQL with the more familiar PostgreSQL (see the jdbc.properties file). But this is all a saying, and here’s a fairy tale: add a dependency

org.codehaus.groovygroovy-all1.8.6


That's almost all, Groovy is already integrated into our project. It remains only to deal with the joint compilation of Java and Groovy.

groovy-eclipse-compiler

For about a year we used the gmaven plugin . There were “pitfalls” in working with him, it makes no sense to recall them, because we switched to groovy-eclipse-compiler . Editing pom.xml

org.apache.maven.pluginsmaven-compiler-plugin2.3.21.6
		1.6UTF-8groovy-eclipse-compilerorg.codehaus.groovygroovy-eclipse-compiler2.6.0-01


Everything with pom.xml is done, run STS and import the project into it. File -> Import -> Maven -> Existing Maven Projects. The “Groovy infected” project looks quite normal.



STS does not swear, this is good, but for the purity of the experiment, you need to collect everything with a maven. We carry out
mvn clean package

and we see the desired in the log:

[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ contactmanager ---
[INFO] Using Groovy-Eclipse compiler to compile both Java and Groovy files


Going to Groovy

So with java we practically said goodbye, we will continue to write in Groovy. There are already quite a few contacts and we want to group these same contacts by type: “family”, “work”, etc.

Let's start with POJO, that is, with PO G O.

Create a src / main / groovy directory, add it to BuildPath, create a package (in our example com.acme.contactmanager.domain)

Right-click on the package -> New -> Groovy class

Call it ... say ... ContactType half-act and write its source code:

@Entity
@Table(name = "CONTACT_TYPES", uniqueConstraints = [
	@UniqueConstraint(columnNames = ["code"]),
	@UniqueConstraint(columnNames = ["name"])
])
class ContactType {
	@Id
	@GeneratedValue
	Integer id
	@Basic
	@Column(unique = true, nullable = true)
	String code
	@Basic
	@Column(unique = true, nullable = true)
	String name
	@Basic
	@Column(nullable = true)
	Boolean defaulttype = false
	@OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REFRESH, CascadeType.MERGE], mappedBy = "contacttype")
	List contacts = null
}


Nothing supernatural, ordinary annotations, except that in arrays, instead of curly brackets, they are square. No modifiers, setter getters , semicolons, everything is clean and tidy.

We inform hibernate that we have a new entity



Add a new field to Contact.java, you can’t do without getter-setters here

	@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.REFRESH, optional = false)
	private ContactType contacttype;
	public ContactType getContacttype() {
		return contacttype;
	}
	public void setContacttype(ContactType contacttype) {
		this.contacttype = contacttype;
	}


We assemble, deploy, and if the hibernate.hbm2ddl.auto = update option is in the hibernate, then we see a new table CONTACT_TYPES and a new field CONTACTS.contacttype_id in the database.

Note: If the database already has contacts, then the hibernate will not be able to set the null restriction, despite the presence of the annotation optinal = false. Filling the links with default values ​​and setting not null restrictions will leave the readers as homework.

Groovy dao

But it’s too early to stop there. The next step is groovy-dao. It, as in the case of java, should consist of a pair of "interface-implementation", otherwise Spring will be unhappy. Repeat the steps with creating the package (this time - com.acme.contactmanager.dao) and creating the ContactTypeDAO.groovy class

interface ContactTypeDAO {
	void addContactType(ContactType contactType)
	List listContactTypes()
	void removeContactType(Integer id)
	ContactType getDefault()
}


Everything is 99% as in java, so let's move on to the implementation. Not the pinnacle of programming skills, but enough for an example. The listContactTypes () method already contains the main charms for which we all started (see comments in the code):

@Repository
class ContactTypeDAOImpl implements ContactTypeDAO {
    @Autowired
    private SessionFactory sessionFactory;
    private Session getCurrentSession() {
        sessionFactory.getCurrentSession()
    }
    @Override
    @Transactional
    void addContactType(ContactType contactType) {
        currentSession.save(contactType)
    }
    @Override
    @Transactional
    List listContactTypes() {
        // в вызовах любых get-методов можно опускать префикс get и пустые скобки
        def result = currentSession.createQuery("from ContactType").list()
        // проверка, что список пустой, выглядит так
        if(!result){
            // Нужен List>? Что может быть проще!
            def types = [
                // кавычки для ключей не обязательны,
                // значения могут быть любого типа
                [name:'Семья', code:'family', defaulttype: false],
                [name:'Работа', code:'job', defaulttype: false],
                [name:'Знакомые', code:'stuff', defaulttype: true]
            ]
            // вместо цикла можно использовать замыкание 
            types.each { type ->
                ContactType contactType = new ContactType(
                        // в любой Groovy-класс по умолчанию добавляется конструктор,
                        // принимающий параметром Map
                        code: type.code,
                        name : type.name,
                        defaulttype : type.defaulttype
                        )
                currentSession.save(contactType)
                // перегруженный оператор << добавляет элемент в список
                // переменная result доступна в контексте замыкания
                result << contactType
            }
        }
        // ключевое слово return не обязательно
        result
    }
    @Override
    @Transactional
    void removeContactType(Integer id) {
        ContactType contactType = currentSession.get(ContactType.class, id)
        if (contactType) {
            currentSession.delete(contactType)
        }
    }
    @Override
    @Transactional
    ContactType getDefault() {
        currentSession.createCriteria(ContactType.class)
                .add(Restrictions.eq('defaulttype', true))
                .uniqueResult()
    }
}


It remains to integrate the specced DAO into Java-service:
public interface ContactService {
    // старые методы где-то тут ...
    public List listContactType();
}


@Service
public class ContactServiceImpl implements ContactService {
    // старые методы где-то тут ...
    @Autowired
    private ContactTypeDAO contactTypeDAO;
    @Override
    @Transactional
    public List listContactType() {
        return contactTypeDAO.listContactTypes();
    }
}


Add a call to the controller:
	@RequestMapping("/index")
	public String listContacts(Map map) {
		map.put("contact", new Contact());
		map.put("contactList", contactService.listContact());
		// список типов контактов для JSP
		map.put("contactTypeList", contactService.listContactType());
		return "contact";
	}


We add localized messages to the messages * .properties files and a drop-down list of types on the JSP (see in the project), we are going to deploy. Check:



Next, you can use Groovy for tests, parse XML, etc. etc.

The source code of the project on GitHub .

Thank you, write to Groovy!

References

Learning to cook: Spring 3 MVC + Spring Security + Hibernate
Groovy Home
Groovy Eclipse compiler
SpringSource Tool Suite
Programming Groovy: Dynamic Productivity for the Java Developer
Lombok project, or Declare war on

PS boilerplate how to add tests to the project is written here . Including tests for web controllers.

Also popular now: