DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Coding
  3. Languages
  4. Groovify CUBA Platform — An Overview of Groovy

Groovify CUBA Platform — An Overview of Groovy

A review of the benefits of Groovy compared to Java, and how to create simple DSLs.

Mario David user avatar by
Mario David
·
Aug. 16, 16 · Opinion
Like (4)
Save
Tweet
Share
5.93K Views

Join the DZone community and get the full member experience.

Join For Free
Groovify CUBA - An overview of Groovy

Developing an application in CUBA Platform is mostly about productivity. It has other advantages, but productivity is probably one of the most important reasons. To ramp up productivity on all stages of CUBA app development, we can invite Groovy to the party.

In this first of two blog posts i will give you an overview about Groovy, so you get a understanding that this might be valuable for you. Why? Because in my opinion the productivity advantage of CUBA falls apart when turn from generating the UI or creating the domain model to the part of programming where you actually want to implement business logic. In this case you are back at the POJO model either in your controller logic or in the services that are just Spring beans.

Coming to CUBA from a Groovy background and haven’t developed in Java for quite some time, it feels a little bit clumsy to go back. This is why i think it’s probably worth thinking about raising the productivity gain (in the business logic side of things) just a little bit by getting the different benefits of the Groovy language onto our CUBA application.

The Elevator Pitch for Groovy

Ok, for an elevator pitch, the easiest thing is to come up with is syntax. We as programmers all love to care about syntax, so there you go. A customer class in Java (~100 LOC):

import java.util.Collection;
import java.util.Date;

public class Customer {

    private String firstName;
    private String lastName;
    private Date birthday;
    private Collection<Order> orders;

    public Customer() {}

    public Customer(String firstName, String lastName, Date birthday, Collection<Order> orders) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.birthday = birthday;
        this.orders = orders;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Collection<Order> getOrders() {
        return orders;
    }

    public void setOrders(Collection<Order> orders) {
        this.orders = orders;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", birthday=" + birthday +
                ", orders=" + orders +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Customer customer = (Customer) o;

        if (firstName != null ? !firstName.equals(customer.firstName) : customer.firstName != null) return false;
        if (lastName != null ? !lastName.equals(customer.lastName) : customer.lastName != null) return false;
        if (birthday != null ? !birthday.equals(customer.birthday) : customer.birthday != null) return false;
        return orders != null ? orders.equals(customer.orders) : customer.orders == null;

    }


    public int calculateTurnover() {
        int totalTurnover = 0;

        for(Order order: orders) {
            totalTurnover += order.getAmount();
        }

        return totalTurnover;
    }

    @Override
    public int hashCode() {
        int result = firstName != null ? firstName.hashCode() : 0;
        result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
        result = 31 * result + (birthday != null ? birthday.hashCode() : 0);
        result = 31 * result + (orders != null ? orders.hashCode() : 0);
        return result;
    }
}

The equivalent in Groovy (~15 LOC):

import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString

@ToString
@EqualsAndHashCode
class Customer {
    String firstName
    String lastName
    Date birthday
    Collection<Order> orders = []

    int calculateTurnover() {
        orders*.amount.sum() ?: 0
    }
}

That’s it. It has the same functionality.

Just in case you think I’m kidding: The Unit test in this article proves that both variants are semantically equivalent.

Groovy basically has a significant better signal to noise ratio. I’m not sure if you noticed it, but there is a little bit of signal in this class. It’s the method calculateTurnover, which is basically the “business logic” if you will. In the Java class it’s very hard to find, because it’s just not visible.

The Differences of Groovy

When comparing both examples, these are some of the things that are different:

  • Removed imports, because of more default imports in Groovy.
  • Removed semicolons where not needed.
  • Changed default visibility scope: private for fields and public for methods, because that’s the defacto default in Java.
  • Removed Getters and Setters, which will be generated by the compiler in the default case.
  • Removed constructors and added a map-based constructor as well as a default one.
  • Removed toString, equals, and hashCode because of the AST-Transformation Annotation.

We could even reduce it further with @Canonical instead of @ToString and @EqualsAndHashCode. A running example of this you’ll find here (which is a very good playground to start with btw.)

Groovy Shines With Maps and Lists

Since bashing about Java Getters and Setters is not my main purpose here, let’s have a look at some more interessting stuff like the implementation of calculateTurnover.

int calculateTurnover() {
    orders*.amount.sum() ?: 0
}

Groovy has some very cool features regarding the Collections API. In the official docs you’ll find a good overview of the features (2. Working with collections). I’ll guide you through a few of them.

Starting with the * Operator. The attribute orders is a collection. When doing a *. on a collection, it will execute the method call after the . for each item in the collection. In this case, getAmount() on every item in the orders list will be called. The result of this is a List with the results of each entry. If you are familiar with functional programming, the Map operation would be something similar (the exact equivalent of it is the collect method in Groovy).

Then, since orders*.amount returns a list, we can call the operation sum on it, which will act according to it’s name. The elvis operator ?: will either return the expression on the left if it’s not null, otherwise it will return the right side.

If this is to scary to you, another alternative implementation would be something like:

int calculateTurnover() {
    def sum = 0
    orders.each {
        sum += it.amount
    }
    sum
}

This example is a little closer to what we saw in the Java class. each is a method on a List, that takes a closure (a function) as a parameter. On each element in the list the function will be executed and it will be the corresponding list item. Same story as Java 8 Lambdas.

There are two additional things that are worth mentioning. First, as I said, each method has one argument: a closure. In Groovy, often times it is not required to use parentheses at all. In this case, it is equivalent to orders.each({ sum += it.amount }) (See the docs — “5. Omitting parentheses” — for more details). Second, return is an optional keyword. If it’s not in place, Groovy will use the last expression of the method as the return value.

Since the headline talks about List and Maps, let’s have a short look at this first class language construct of Groovy. Here we have a few examples on how Groovy handles Maps:

def map = ["hello" : "world", "lorem" : "ipsum"]

assert map["hello"] == "world"
assert map.lorem == "ipsum"

// create a customer with a map constructor
def customer = new Customer([
firstName: "Mario", 
lastName: "David", 
orders: [
new Order(amount: 150)
]
])

The map constructor gives you a cartesian product on the possible constructors. Using a map as the parameter list in general (not just in the constructor) can be a very good idea, because it drastically increases the readability of the code compared to parameter lists where the third and the firth parameter is a boolean, and nobody is able to know what that actually indicates. It literally gives you named parameters like in C# or Javascript (when passing a JSON object to a function).

More differences that differtiates Groovy from Java can be found in the Groovy style guide.

By the way, == is not a reference comparison like in Java. Instead the equals method of the objects are called, because like before: Groovy changes default Java behavior to something that makes sence in most cases.

Syntax is Just Syntax — There Are More Things

Although this syntactic sugar compared to Java is neat, there are other things to keep in mind before switching your whole project from one language to another. Since this discussion would clearly go beyond this blog post, i’ll just go over them and give you some resources to dig down further.

Performance is one of these issues. In the beginning, before invokedynamic was build into the JVM, creating performant dynamic languages on the JVM was pretty hard. Nowadays Groovy gives the user choices about speed with @CompileStatic. More information you’ll find at this InfoQ article from 2012 as well as this SE Radio podcast with Cédric Champeau. But whenever thinking about performance, keep in mind the two rules of software optimization.

Next up, we have dynamic-, static-, strong- and duck-typing. All of these attributes are correct for Groovy. You basically can def all the things if you want to. The runtime will figure out the rest on your behalf. This is potentially not the best thing to do, so Groovy gives you choices. When you want to use types and have that checked by the compiler there are options like @TypeChecked or @CompileStatic. Have a look at this article optional typing in groovy for a few insights.

Aditionally there is a Metaobject Protocol (MOP), which lets you do runtime meta programming and since Groovy is compiled, you can do compile time metaprogramming with AST-Transformations. An example of runtime meta programming is the following example from a Grails (a Groovy based Web framework) Domain class:

class Post{

String content
String teaser
Date dateCreated
Date lastUpdated

static hasMany = [comments: Comment]

}

myPost = Post.findByTeaserLike("%my teaser%")

findByTeaserLike is a method that does not exist at compile time. It is a method that is evaluated at runtime and build and execute a SQL Query that queries for a post entry where the column teaser is like %my teaser%. A good insight on this feature (which is based on methodMissing) you’ll find in the article Groovy Goodness: Create Dynamic Methods.

Based on this meta programming feature comes another one: domain specific languages. You can create languages that look like this:

take 2.pills of chloroquinine after 6.hours

// equivalent to: take(2.pills).of(chloroquinine).after(6.hours)

To create a DSL in Groovy really is a breeze. This is perhaps not directly relevant for the developers (although it could be), doing this right can give your process a dramatic additional performance boost and include other people be part of the process as well. Have a look at the book domain specific languages from Martin Fowler for further reading.

Grooovy Can Make a Difference

To wrap this up, I think you get a good feeling about the differences that Groovy can make. The syntactic sugar together with more options open up possibilities for the users of this language.

As I already wrote last time, software developers paychecks are the driving cost factors in most IT efforts. This is especially true for software development. Any opportunity to get better in this regard will increase the overall outcome. CUBA has helped us with different things to go down this road pretty far. To use Groovy in this scenario is just another one of these steps that focuses on the business part of things.

If you want to take a deeper look into Groovy (and i hope i could encourage you to do so), there a very good book about Groovy, called Programming Groovy 2 form Venkat Subramaniam which goes much deeper in the described topics.

In the second part of this two part blog post, I will go trough the actual integration. We’ll have a look on how to enable Groovy in the CUBA app and take look at some other integration possibilities as well.

Groovy (programming language) Java (programming language) IT

Published at DZone with permission of Mario David. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Cloud-Native Application Networking
  • Silver Bullet or False Panacea? 3 Questions for Data Contracts
  • Too Many Tools? Streamline Your Stack With AIOps
  • Problems of Cloud Cost Management: A Socio-Technical Analysis

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: