composite builds in gradle

In the lab today, I got a nice Gradle question. I’m answering it here on the blog so all the students can see it. (and anyone else who is curious).

The use case

We have a common library that this year (and all future year’s robots should use). However, this is the first year of competition with the library so it is likely we will need to make changes to it and rebuild at competition.

Constraint #1 – lack of wifi

For any professionals reading this wondering why we don’t use Jitpack, github or any other hosting – internet is “tricky” at competition.; It is common for there to not be any wifi in the pit and you aren’t allowed to make your own hotspot. So we need a solution that works without internet and easily lets us re-build on the same machines.

Constraint #2 – reuse

I really want the library (StuyLib) to stay in it’s own repository and not have the build file “polluted” by any changes. Why you ask? So it stays a library and not something we copy/paste from year to year.

The solution

Composite builds. Gradle has a nice system for composite builds that lets you refer to one build from another.

Directory structure

  • git clone https://github.com/StuyPulse/StuyLib
  • git clone https://github.com/StuyPulse/fantastic-spork (or any other robot)
  • That means StuyLib and fantastic-spork are in parallel directories

Updates to StuyLib

Yes, I know, I said I didn’t want updates. The only things I added were a group and version variable. That gives the artifact a proper name. (group id = com.stuypulse, artifact id = StuyLib, version = 1.0.0). StuyLib still doesn’t know it is part of a composite build.

plugins {
   id "java"
   id "edu.wpi.first.GradleRIO" version "2020.1.2"
}

// add the following two lines
group = 'com.stuypulse'
version = '1.0.0'

sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11

Updates to Robot

At end of settings.gradle, add this line:

includeBuild '../StuyLib'

Then in build.gradle, add a dependency on StuyLib

def ROBOT_MAIN_CLASS = "com.stuypulse.robot.Main"

// add a dependency
dependencies {
  implementation('com.stuypulse:StuyLib:1.0.0')
}

Testing

First, I tested that I could build each independently:

  1. cd StuyLib
  2. ./gradlew build
  3. cd ..
  4. cd fantastic-spork
  5. ./gradlew build

Then I added a class that used existing functionality in StuyLib to fantastic-spork

package jb;

import com.stuypulse.stuylib.util.*;

public class Jeanne {
  StopWatch s;
//  String str = StopWatch.TEST;
}

I re-ran the ./gradlew build in fantastic-spork and good. Then I added one line to StopWatch:

public static final String TEST = "test";

I uncommented the line in Jeanne.java. Then for the key part. I re-ran ./gradlew build in fantastic-spork and it worked. I was able to recompile fantastic-spork and have it see a change in StuyLib without having to rebuild StuyLib.

Plus this change to StuyLib only exists on my machine which proves it is being used.

10 years later… female programmers and programmers to be

Ten years ago, I wrote a blog post entitled Female Programmers and Programmers to Be. It was largely a response to Kathy Sierra’s tweets on the topic. Now that I have ten years more experience, I decided to look back what I wrote and see how my thoughts on the matter have evolved.

Significance of being a “Woman In Tech”

The 2009 me wrote:

While I certainly haven’t been in the field as long as Kathy, I am a female programmer.  And I haven’t really thought about it since college.  Until recently.  It’s not significant to me; I don’t think it is significant to people I work with.  And yet in some ways it is.  My response to this tweet was:

@KathySierra sorry; you’re a VISIBLE female programmer & a role model for the next generation(aka me); don’t have any at work so branch out -Jeanne Boyarsky

And this is why I’ve been thinking about it.  Whether I notice or not, I am starting to become a role model to some people.  I know because they told me!  Sometimes it is people I know and sometimes it is people who read my posts on JavaRanch.

Well, now I’m definitely a role model! I’ve been a FIRST robotics mentor for over ten years, a regular conference speaker and a Java Champion. I think my 2009 self nailed it with the VISIBLE comment.

Ten years later, I do have more female programmer role models. (Phew.) Most of them either aren’t from work or are about my age though. Which I suppose makes sense. There weren’t going to spontaneously be more female programmers 10-20 years older than me. I also realized I was only counting people who chose the path over development over management. Between having a bigger network and time having passed, I definitely have more female peers and role models that I know in real life.

I do feel the same way as 10 years ago in that most of the time gender doesn’t matter, but every so often it does. I’ve been lucky that for me that has mostly been in the space of empowering others and less in the space of negative personal experiences. I also learned that I go through a long process in my head when I have to deal with the whole female role model thing. When asked something like being on a women in tech panel, my thought process is:

  1. Ugh. I just want to code.
  2. I want everyone who likes to code to feel like they can be a developer.
  3. I remember when almost all of my role models were men.
  4. Being seen helps others.
  5. Ugh. I’m going to have to talk and think about it.
  6. Grumble. I wish this didn’t matter.
  7. I remember in college being told this wouldn’t be a problem by now.
  8. Sigh. All right, all right I’ll do it.

In some ways, I was “lucky” that I got my exposure to “girls shouldn’t do science of IT” folks in middle school and high school. I built up immunity and didn’t care what they thought. It turns out that having a high school teacher say that in class definitely makes you think. I decided that programming was too fun to worry about it. My only regret was not making a formal complaint to the school administration at the time. (Instead I taught science to the girls in the class who were struggling so they got higher averages. Doing that during his rants about girls was sorta fun.)

I also had early exposure to a manager who felt cursing at his staff was appropriate. (This was not a gender thing.) But it gave me the “opportunity” to decide what was a line for me. To this day, I am unwilling to be cursed at at work. (Note to colleagues: I don’t care if people curse around me; I do care if it is directed at me.) I practiced in my head what I would say/do. I hope I’m never in the situation where I have to find out if I’m brave enough to test out whether I would. It’s “easy” to say what you’d want to do. It’s not easy that situation. So when you “armchair coach” a woman on what she should do/say, remember it isn’t as easy as it appears.

High schoolers

@jeanneboyarsky agree in principle, just that conference keynoters are NOT on teen girl’s radar and don’t “count” as visibility/motivation. -Kathy Sierra

This school year, I started volunteering as a mentor with FIRST robotics as a high school programming mentor.  The lead student programmer is also female. 

I agree that conference keynoters/speakers are not on teen girl’s radar (at least not at industry conferences.) I’ve spoken a few times at StuySplash (a conference run by a FIRST robotics team for other teams.) Most of the audience was high schoolers.

I think I replied wrong though. Having female conference speakers isn’t for high schoolers. It’s for future conference speakers. There’s that thing about how men apply for jobs when they meet a smaller percentage of the requirements than women. That applies to conferences too. I think women seeing female speakers would make them more likely to apply. It also helps men see there are strong female techies even if they don’t work someplace that is true.

Female Architects

@KathySierra: “women speakers in tech?” I always wonder why ‘women’ are different. Don’t we want good _people_ in these sessions? –Steve Johnson

And absolutely favor strength over gender when choosing conference speakers.

Where I work, there aren’t yet any female architects. And by that I mean the really senior folks who have been doing this 20-30 years like Bear Bibeault and Ernest Friedman Hill rather than the watered down “developer with 7 years experience” definition.

Yes, I want to be an architect someday.  But I want to get there because I’m good at what I do, not because I am female.

One of the nice things about getting rejected as a JavaOne speaker so many years in a row was that I knew I didn’t get picked for being female! (I got picked the year after there was a video of my giving an awesome talk on youtube). I do think I got an opportunity/nudge to give a full day training at Dev Nexus because I’m female. But I had also given a shorter version of that training at JavaOne.  I definitely still think it is important to favor strength over gender. But I think encouragement is ok. (Back to the “but I don’t meet 100% of the requirements” thing).

I’m pleased to say 10 years later that the statement of not having any female architects at work is no longer true! (I’m not an architect; I was and then I moved to a team where there isn’t a need for one. I’m still a tech lead and work)

What can we do

  1. Like what you do; be passionate about what you do – Male or female, this is the core of why technology is fun!  If you happen to be female, let this excitement shine through and let others see it.  I’m volunteering as a programming mentor for robotics because I enjoy it.  Being a positive role model for the students is a side effect.

  2. Point out the “she” – If you are female and someone refers to you as “he” or “sir”, correct them.  This is how we introduce visibility into the fact that there are strong techies out there.  Scott Selikoff does so if someone calls me “he” in a blog comment. Some people do this so often at JavaRanch that Campbell Ritchie has made it a running joke. But it helps.  It serves as little reminders that we do have strong female technical females running around.  Not to the the teens of course.  But to the existing programmers.

  3. Look to the future – Things change over time.  The senior architects of the today were largely born in the 50’s, 60’s and 70’s.  This was before people had the internet in their homes.  The students of today are growing up with social networking.  Computers aren’t as geeky.  There is more social interaction in the job.  In another couple of decades people my age will be those senior architects and then there will be more female role models.

I agree with all three of these pieces of advice from 2009. I have two more:

4) Refer to the people on your team. When interviewing, mention accomplishments of multiple people on the team. This provides an opportunities to show you have women, people from “ethnic” groups, etc without making a big thing out of it.

5) Encourage people do things they are almost ready for. (Notice I said “people” not “women”. This applies to guys too, especially if they are reserved or not reaching for opportunities.” Also, craft opportunities for them to push themselves in ways that are smaller so not as scary. For example, I recently asked an entry level teammate to do five minutes of a presentation with me. (I had the other 45 minutes.)

OCP 11 Book Bonus: Creating a HSQL Database/Stored Procedure in Java 11

For the PreparedStatement section of chapter 10, we used Derby. We recommend following the creating Derby instructions first.

For the CallableStatement section we used HSQL (Hyper Structured Query Database). We switched because Derby doesn’t use SQL based stored procedures which are the most common form.

You don’t need to know anything about creating stored procedures for the exam. You do have to know how to call them. This blog post is for readers who have purchased our book, OCP: Oracle Certified Professional Java SE 11 Programmer II Study Guide: Exam 1Z0-816 and want to follow along. It also includes the database installation instructions and setup code so you can simply copy/paste it. The actual book covers what you need to know for the exam.


This blog post assumes you are reading chapter 10 of our OCP 11 book for 816 exam and have gotten up to the part that references this blog post.


Download HSQL

Option 1: Download the hsqldb.jar from Maven Central

Option 2: HSQL is an open source database. It is really easy to install and use. To install:

  1. Go to the HSQL home page.
  2. Click on the link for the latest version. (At the time of this blog post, that was 2.5.0)
  3. Click through the many screens until it downloads.
  4. Download the zip file and unzip it. This will create a folder named something like hsqldb-2.5.0. Drill down to hsqldb and then lib to get the hsqldb.jar file.

Copy this hsqldb.jar to someplace convenient on your machine. The same directory you picked for the derby jar is a good choice.

Creating your initial database

To start out, copy this code into a file named SetupHsqlDatabase.java.

import java.sql.*;

public class SetupHsqlDatabase {

    public static void main(String[] args) throws Exception {
        String url = "jdbc:hsqldb:file:zoo";
        try (Connection conn = DriverManager.getConnection(url);
             Statement stmt = conn.createStatement()) {

            run(conn, "DROP PROCEDURE read_e_names IF EXISTS");
            run(conn, "DROP PROCEDURE read_names_by_letter IF EXISTS");
            run(conn, "DROP PROCEDURE magic_number IF EXISTS");
            run(conn, "DROP PROCEDURE double_number IF EXISTS");
            run(conn, "DROP TABLE names IF EXISTS");
            run(conn, "DROP TABLE exhibits IF EXISTS");

            run(conn, "CREATE TABLE exhibits ("
                    + "id INTEGER PRIMARY KEY, "
                    + "name VARCHAR(255), "
                    + "num_acres DECIMAL(4,1))");

            run(conn, "CREATE TABLE names ("
                    + "id INTEGER PRIMARY KEY, "
                    + "species_id integer REFERENCES exhibits (id), "
                    + "name VARCHAR(255))");

            run(conn, "INSERT INTO exhibits VALUES (1, 'African Elephant', 7.5)");
            run(conn, "INSERT INTO exhibits VALUES (2, 'Zebra', 1.2)");

            run(conn, "INSERT INTO names VALUES (1, 1, 'Elsa')");
            run(conn, "INSERT INTO names VALUES (2, 2, 'Zelda')");
            run(conn, "INSERT INTO names VALUES (3, 1, 'Ester')");
            run(conn, "INSERT INTO names VALUES (4, 1, 'Eddie')");
            run(conn, "INSERT INTO names VALUES (5, 2, 'Zoe')");

            String noParams = "CREATE PROCEDURE read_e_names() "
                    + "READS SQL DATA DYNAMIC RESULT SETS 1 "
                    + "BEGIN ATOMIC "
                    + "DECLARE result CURSOR WITH RETURN FOR SELECT * FROM names; "
                    + "OPEN result; "
                    + "END";

            String inParam = "CREATE PROCEDURE read_names_by_letter(IN prefix VARCHAR(10)) "
                    + "READS SQL DATA DYNAMIC RESULT SETS 1 "
                    + "BEGIN ATOMIC "
                    + "DECLARE result CURSOR WITH RETURN FOR " +
                    " SELECT * FROM names WHERE name LIKE CONCAT(prefix, '%'); "
                    + "OPEN result; "
                    + "END";

            String inOutParam = "CREATE PROCEDURE double_number(INOUT num INT) READS SQL DATA\n" +
                    "  DYNAMIC RESULT SETS 1 " +
                    "  BEGIN ATOMIC " +
                    "  SET num = num * 2; " +
                    "  END";

            String outParam = "CREATE PROCEDURE magic_number(OUT num INT) READS SQL DATA\n" +
                    "  BEGIN ATOMIC " +
                    "  SET num = 42;" +
                    "  END";

            run(conn, noParams);
            run(conn, inParam);
            run(conn, outParam);
            run(conn, inOutParam);

            printCount(conn, "SELECT count(*) FROM names");
        }
    }

    private static void run(Connection conn, String sql) throws SQLException {
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.executeUpdate();
        }
    }

    private static void printCount(Connection conn, String sql) throws SQLException {
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            ResultSet rs = ps.executeQuery();
            rs.next();
            System.out.println(rs.getInt(1));
        }
    }
}

To run the program, you need to include the hsqldb jar file in your classpath. See the bottom of the creating Derby instructions FAQs if you aren’t sure how to do to this.

For example:

java -cp "<pathToHsql>/hsqldb.jar" SetupHsqlDatabase.java

If all goes well, the program will output the number 5.

What does this program actually do?

This program starts by doing the same thing as the Derby one. It then creates the stored procedures used in the book.

HSQL will create some “zoo” files in your current directory for the database and logs.

What does “user lacks privilege or object not found in statement” mean?

In HSQL, it means “something went wrong.” It could be a runtime error in your stored proc. It could be that you aren’t calling it right. Confusing message, I know.