Chariot Training Classes

Training Courses

I run Chariot's training and mentoring services. We provide training in AngularJS, HTML5, Spring, Hibernate, Maven, Scala, and more.

Chariot Education Services

Technology

Chariot Emerging Tech

Learn about upcoming technologies and trends from my colleagues at Chariot Solutions.

Resources

Chariot Conferences

Podcasts

Entries in spring-roo (25)

Tuesday
May222012

Spock and Roo = easier add-on testing, part 1

Hey all...

I've been working on my add-ons. If you're reading this from my website, head over to the Silly Weasel menu and get the repository OBR to install my Spock add-on when trying this.

You are running Groovy in Roo? Shame on you!

Hey, before I was a Roo in Action author, I was a huge fan of Grails. I still am, because Groovy + your favorite APIs is so much more concise to program against than with stock Java. So, one of my backburner projects was getting Groovy to work on Roo.

Roo doesn't like Groovy (yet)

It turns out the reason is AspectJ. Right now, our projects are all compiling against the AspectJ API (version 1.2.x if memory serves). The problem is that Groovy's bytecode is not compatible with AspectJ, at least in terms of getting it to compile in the same Maven compiler step. I looked on the AspectJ timeline, and saw AspectJ 1.5 and 2.0 will support Groovy as a target for weaving. Coolness!

But that doesn't stop us from using it to test!

Yep, that's right. Turns out you can attach the Groovy compiler to your test phase, and it works. By the time your tests are compiling, the main classes have been compiled and weaved with that AspectJ goodness. So your ITD methods are there, and you can use any old testing tool you want to test 'em.

Note, I think you may have issues with my approach, if you are going to use the DataOnDemand testing framework, but so far, it seems like it works well.

My example for the evening - testing with mocks for Add-on Commands

Ok, here's a practical example. My jQueryUI add-on command class delegates the isAvailable and install commands to the Operations Implementation class, JqueryuiOperationsImpl. I wanted to start working up the test coverage for this add-on, because right now I am failing my hudson build due to a lack of test coverage.

So, here is a Groovy Spock specification, which I named JQueryuiCommandsTest.groovy and placed in src/test/groovy (after installing the maven script I'll reference below it). I've even created a Spock Roo add-on for you to use to set this up in your own projects.



package org.sillyweasel.addons.jqueryui

class JQueryuiCommandsTest extends spock.lang.Specification {

    JqueryuiCommands commands
    JqueryuiOperations operations

    def setup() {
        operations = Mock()
        commands = new JqueryuiCommands();
        commands.operations = operations;
    }

    def "when calling availability we defer to implementation" () {
        when:
        boolean result = commands.isApiInstallCommandAvailable()

        then:
        1*operations.isInstalljQueryCommandAvailable()
    }

    def "when calling ui availability we defer to implementation" () {
        when:
        boolean result = commands.isInstalljQueryUIAvailable()

        then:
        1*operations.isInstalljQueryUICommandAvailable()
    }

    def "when calling installjQueryApi we defer to jquery operations method" () {
        when:
        commands.installjQueryApi()

        then:
        1*operations.installjQueryApi();
    }

    def "when calling installjQueryUI we defer to jquery operations method"() {
        when:
        commands.installjQueryUIApi()

        then:
        1*operations.installjQueryUIApi();
    }


}

How did you get this to work?

I basically stole the configuration for Spock and Maven, and tweaked it a bit. Here are the relevant bits of my Maven build:

<dependency>
    <groupId>org.spockframework</groupId>
    <artifactId>spock-core</artifactId>
    <version>0.6-groovy-1.8</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.spockframework</groupId>
    <artifactId>spock-spring</artifactId>
    <version>0.6-groovy-1.8</version>
    <scope>test</scope>
</dependency>

...

<plugin>
   <groupId>org.codehaus.gmaven</groupId>
   <artifactId>gmaven-plugin</artifactId>
   <version>1.4</version>
   <configuration>
       <providerSelection>1.8</providerSelection>
       <source>src/test/groovy</source>
   </configuration>
   <executions>
       <execution>
           <goals>
               <goal>testCompile</goal>
           </goals>
       </execution>
   </executions>
   <dependencies>
       <dependency>
           <groupId>org.codehaus.gmaven.runtime</groupId>
           <artifactId>gmaven-runtime-1.7</artifactId>
           <version>1.3</version>
           <exclusions>
               <exclusion>
                   <groupId>org.codehaus.groovy</groupId>
                   <artifactId>groovy-all</artifactId>
               </exclusion>
           </exclusions>
       </dependency>
       <dependency>
           <groupId>org.codehaus.groovy</groupId>
           <artifactId>groovy-all</artifactId>
           <version>1.8.6</version>
       </dependency>
       <dependency>
           <groupId>org.spockframework</groupId>
           <artifactId>spock-core</artifactId>
           <version>0.6-groovy-1.8</version>
       </dependency>
       <dependency>
           <groupId>org.spockframework</groupId>
           <artifactId>spock-spring</artifactId>
           <version>0.6-groovy-1.8</version>
       </dependency>
   </dependencies>
</plugin>

Wednesday
May162012

Roo Add-On Development, Part the Second - Testing XML Configurations

In the last post, we discussed unit testing Roo add-on code. I feel this is just as vital as testing any other piece of Java code, considering that every time you run the command in the container you literally have to boot it, update the OSGi bundle, and then test. The feedback loop is too long to fix little, annoying bugs like not properly parsing an XML document.

Roo "Advanced add-ons" and Configuration

Let's assume we're not stellar coders. Let's even assume that we aren't the best XML developers. I'm shining a bright line at myself here.

With the CoffeeScript add-on, we want to manipulate the pom.xml file - something we don't need a container to do. Roo uses that good ole' built-in JAXP library (and Apache implementation of course). As Ben Alex would say, "stock standard Java." So, we should be able to easily unit test it.

The CoffeescriptOperationsImpl class - under test!

Last blog we showed you how to test the CoffeescriptCommands object, which delegates calls to the CoffeescriptOperations OSGi bean, which is implemented by the CoffeescriptOperationsImpl class. This is where the add-on's work is being done. So, let's test it.

Setting up the test class and Mockito

Like last time, we need to configure Mockito. We'll assume you've read up on that post and have installed the proper dependencies.

We need to test that our operations code works, and that it calls the proper Roo services. So, let's create our bean under test, and then mock the collaborator:

public class CoffeescriptOperationsImplTest {
  private CoffeescriptOperationsImpl coffeescriptOperations; 

  @Before
  public void setUp() {
    coffeescriptOperations = new CoffeescriptOperationsImpl();
    coffeescriptOperations.projectOperations = 
      Mockito.mock(ProjectOperations.class);
  }
  ...
 

Again, we manually create our class under test, and configure our mocks, in keeping with typical unit tests of components. I had to widen the visibility of the projectOperations reference to 'friendly' access - so that this class, which lives in the same package as the code under test, can see it and replace it with a mock.

h2. Reviewing our method under test - setup()

Let's look at our setup method:

  public void setup(String coffeeDir, 
                  String outputDirectory, boolean bare) {
    String moduleName = projectOperations.getFocusedModuleName();
    Element coffeePluginElement = getCoffeeScriptPluginElement();
    Document document = coffeePluginElement.getOwnerDocument();

    if (bare) {
      addTextElement(document, coffeePluginElement, "bare", "true");
    } else {
      addTextElement(document, coffeePluginElement, "bare", 
        COFFEE_DEFAULT_BARE_SETTING);
    }

    if (coffeeDir != null && coffeeDir.trim().length() > 0) {
      addTextElement(document, coffeePluginElement, "coffeeDir", coffeeDir);
    } else {
      addTextElement(document, coffeePluginElement, "coffeeDir", 
        COFFEE_DEFAULT_SRC_DIRECTORY);
    }

    if (outputDirectory != null && outputDirectory.trim().length() > 0) {
      addTextElement(document, coffeePluginElement, "coffeeOutputDirectory", outputDirectory);
    } else {
      addTextElement(document, coffeePluginElement, "coffeeOutputDirectory", 
        COFFEE_DEFAULT_OUTPUT_DIRECTORY);
    }

    projectOperations.addBuildPlugin(moduleName, new Plugin(coffeePluginElement));
  }

It's clear that we have a LOT of branches in this code, but that's because we're taking input from our command itself. I'll lie here, and tell you that I've written tests against all of these branches, but again, I said I'm lying - and in a further lie, I'll tell you that "I'm gonna get to it!" However, here's why lying doesn't help - I'm sure I have bugs in this code, and I really need to verify it all.

Oh, and I was thinking - I have a few private methods to help me keep the code organized and modular... Perhaps I should test those too but that leads the way of code smell... Interesting read BTW.

Reviewing the tasks in the method

Ok, the method does a few things:

1. Asks a helper method for the Configuration XML file as a basis for the Maven plugin.
2. Does a couple of gyrations so that we can maniuplate the plugin nodes with the DOM API - since Roo's Maven object model is essentially a thin wrapper around the XML API we have to think more in XML. This is something I'll be exploring in the future.
3. Sets the options the user passed in.
4. Adds the build plugin to the Maven build.

Ultimately, though, we need to see if:

1. Given a call to setup(), and the appropriate parameters,
2. Does the Plugin contain the proper information

Our test method for the setup process

Ok,

  @Test
  public void testSetupCoffeescript() {

    when(coffeescriptOperations.projectOperations
       .getFocusedProjectName()).thenReturn("foo");

    // a way for Mockito to grab passed input parameters for testing
    ArgumentCaptor<Plugin> pluginCaptor = 
       ArgumentCaptor.forClass(Plugin.class);

    // invoke our method
    coffeescriptOperations.setup("baz", "bar", false);

    // did we call addBuildPlugin? Also, notice we capture what the
    // method passed to the mocked projectOperations.addBuildPlugin method
    // for the plugin XML Element code
    verify(coffeescriptOperations.projectOperations)
       .addBuildPlugin(any(String.class), pluginCaptor.capture());

    // Since the plugin has been called and we've captured the method's 
    // second argument, we'll pluck it out and take a gander...
    Plugin coffeescriptPlugin = pluginCaptor.getValue();

    // make sure they passed something!
    assertNotNull(coffeescriptPlugin);

    // checks against the model
    Assert.assertEquals("false", coffeescriptPlugin.getConfiguration()
        .getConfiguration().getElementsByTagName("bare")
        .item(0).getTextContent());

    Assert.assertEquals("bar", coffeescriptPlugin.getConfiguration()
        .getConfiguration().getElementsByTagName("coffeeOutputDirectory")
        .item(0).getTextContent());

    Assert.assertEquals("baz", coffeescriptPlugin.getConfiguration()
        .getConfiguration().getElementsByTagName("coffeeDir")
        .item(0).getTextContent());
  }

Mockito's ArgumentCaptor

I guess this is really a testing tools article, rather than a Roo article.

The ArgumentCaptor API is really useful to see what the values were for a mock that was called by your class under test. This is a way to verify that we were passing in the right plugin configuration to our Roo projectManager, which, after all, we aren't testing. That's the Roo team's job!

Wrap-up

Looking at it from a distance, Roo is just a Java platform that generates, manipulates and configures applications. So it can really do anything. However, rather than testing by re-deploying 10 times, we can run a fast Junit test 10 times instead.

If you go to my Silly Weasel link at the top of the blog page, you'll see the OBR URL for getting my Coffeescript, jQuery and (soon) Site add-ons. You can browse my maven repository (the same URL without the repository.xml ending) and grab the source for anything I've released.

Please send me comments if you'd like to add to this discussion.

Best,

Ken

Sunday
May062012

Don't call names - Roo's Tag with a tag problem

Eureka, ish..

I was trying to find time to debug a problem that's been on my backlog for a while, and someone else ran into it. A reader over on the Manning Spring Roo in Action forum was getting hit with a 400 invalid request error when trying one of the samples from the book (the many-to-many example).

A while back, I ran into this problem - my m:m arrangement was between Courses and Tags, and the field name of the actual tag in the Tag entity was called 'tag'. When I did this, I got the same error. Someone hit it in the forums, we renamed it to 'name' and committed our code, and I forgot about it for a while.

My theory was that the type converters somehow were generated wrongly. Nope, I have a " target="_blank" class="offsite-link-inline">JUnit test to review that does it properly, so that's not the problem.

Actually, the problem is with the type conversion, but it's not the fault of the Roo code for type converters (to my knowledge so far). They are just doing what they are supposed to do.

The REAL Problem

First of all, my theory on the bad type converters was wrong. I proved it by writing a set of tests to make sure I a) understood the true workings of the generated type converters and b) that they worked. In the next edition of Roo in Action I think I need to devote some time to these. See the attached sample at the end to see my tests. Here is how they work (example - the tag):

Type Conversions

  • Convert an object -> a single line String representation as a default label for a given dropdown entry. (converterFactory.getTagToStringConverter())
  • Hydrate a Tag via a String representation of the key (converterFactory.getStringToTagConverter())
  • Hydrate a Tag via a primary key value (converterFactory.getIdToTagConverter())

All of these work just fine when tested individually, which they should.

The Tag to String converter is used in dropdowns for the many-to-many relationship, so that when the tag editing screen (which owns the relationship) allows a user to select one or more courses, it just shows the field values separated by spaces.

So, now what?

Spring MVC creates forms with a set of assumptions, including the fact that the form will be of a certain bean instance root. This is provided by specifying the modelAttribute in Spring MVC, but since Roo does this for us, we aren't in charge of that in a scaffolded UI.

Here is the create.jspx file for reference.

The scaffolded value is generated by create.tagx, which uses this code:

<form:form action="${form_url}" method="POST"
   modelAttribute="${modelAttribute}" enctype="${enctype}" 
   onsubmit="${jsCall}"> ...

The essential problem I think we're running into with the samples the way they are put together is:

  • The "bean context" / model attribute name of the form being submitted is expected to be 'tag'
  • The form is submitting fields in this form with names such as description, id, and also tag
  • Spring MVC is spitting nails on the fact that you have tag.tag in your request. It wants to convert the nested tag into another Tag object, by hydrating it (probably to support recursive relationships or something). Well, it takes your String for the tag label and tries to take it through idToTagConverter() which fails on a numeric parse.

How to fix For now, avoid using the entity name as a field name in a given entity. I need to do more extensive testing to see why this is happening. This is something that I should know by heart, I guess, but I've been wrestling with other areas of Java and Roo and haven't been as connected to the web forms as I used to be.

If anyone wants to take this on, I have posted the code sample in the original Manning thread (look on the second page) with the junit tests included. Just create a course, then create a tag with the 'tag' field of any alpha value.

[b]The sample test[/b]

I created a spring junit test to check my assumptions (I imported hamcrest-all for matching support to make the assertions readable quickly, the pom includes org.hamcrest:hamcrest-all:1.1).

Thursday
Mar012012

Quizzo - it's THURSDAY? Must go into the Dojo and meditate

You know how if you don't have anything nice to say, don't say it at all? Mmm hmm... Except it was a conversation with myself that started "why the heck don't you know THAT?"...

Where the heck were you?

Ok, ok, I was busy with my day job. Training at Chariot is really getting busy, which is great because I run that group! If you're looking for public or private training in Spring, Maven, Hibernate, and a number of other technologies, check us out.

Shameless plug-meister, what are you doing with the quizzo??

Ok, it's back to reality. I've been taking an alternate path with the quizzo UI. Since Chariot Day is a chance to stretch a bit, I figure I'd do the admin and perhaps main front-end as a rich Javascript UI, Roo-style. That comment about not saying anything nice? It was about a library I wish Roo would leave behind. It's called Spring Javascript.

Spring Javascript?

If you're thinking "Cool, a Spring Container in Javascript" - a) stop RIGHT there, dude, and b) it's not what you think. c) that's pretty nifty, but I understand there is a movement out there for MVC and strong binding in the Javascript community. I know nothing about it, but some of Chariot's mobile team do. Read here, here, here, here, and oh, here. Did I mention we're a consulting firm?

Spring Javascript is a Javascript library written for the WebFlow project. The idea was that if you wanted to roll out client-side validation, ajax forms, or any widgets from a Javascript toolkit, you'd use this library. It also has this wrapper around doing partial rendering of Ajax Tiles (or JSF fragments, I think). Nifty.

The Spring Javascript library is a thin wrapper around a Javascript toolkit called Dojo.

Bow to your Sensai - what is Dojo?

Roo's view layer heavily uses Dojo. Those neat little client-side validations? Dojo. The panels with the little titlebars? Dojo - that's the dijit.layout.TitlePane.

The reason for choosing Dojo makes sense for me. At the time it was a very comprehensive widget toolkit and in 2008 it was gaining in popularity. Just look at the date of the books published and you'll get the idea. Sitepen is a supporter of the library and IBM and a number of large organizations use it. It has a great open community as well, and is funded by a not-for-profit organization.

But then a lot of developers turned left at jQuery. The focus has been on a more wide-open platform, with the curation of components being primarily the user's job. Think "platform-and-plugins" and you're on to it.

Dojo hasn't changed their approach. In fact, I really like the concept of how they focus themselves on curation, incorporation of experimenta components into an extensions library, and the coherence of the whole library.

So, what about Spring Javascript

The reason I'm not a fan of Spring Javascript is that it is kind of an artifact of where the thinking was in 2007/2008, and hasn't moved on. Spring Javascript hides about 40% of the construction of Dojo widgets (known as Digits (dijit)). But it's a leaky abstraction; you need to know Dojo to program it after all, and Roo only really uses it for validation sugar.

Here is a Spring Javascript snippet to create a title pane, which you can find in WEB-INF/tags/utils/panel.tagx:

  
    <div id="_title_${sec_id}_id" class="panel">
    <h2>${sec_title}</h2>
      
      <jsp:doBody />
    </div>

I've highlighted the lines where Dojo isn't hidden. You're mounting a Dojo TitlePane, and to do so, you need to know:

  • The Dojo specifics of the class
  • The various attributes of the widget
  • What widget (dijit) to import

So, not really encapsulating the framework.

How Dojo wants to be used

Dojo is a flexible framework. It has at least three ways to use it. First, you can programmatically create a component like a title pane.

In Javascript:


  dojo.require("dijit.TitlePane");

  var tp;
  dojo.addOnLoad(function(){
      tp = new dijit.TitlePane({title:"Quiz Administrator", content: "Show my content here"});
      dojo.byId("someDiv").appendChild(tp.domNode);
  });

In HTML with a page parser (this is the pre-Dojo 1.7 version):

  <div dojoType="dijit.layout.TitlePane" title="hiya dude">
     <p>This is content for my title pane</p>
  </div>

And in 1.7 and above using the new html 5 data attributes:


  <div data-dojo-type="dijit.layout.TitlePane" data-dojo-props="title: 'hiya dude'">
     <p>This is content for my title pane</p>
  </div>

So, where's the pain?

Ok, so a couple of problems exist for me when trying to RIA-ize a Roo application:

Dojo != Spring Javascript

The Dojo toolkit is under constant update We're on 1.7.2 in the community, and they are moving into mobile, HTML 5, media controls, etc. Spring Javascript embeds a custom build, and the most recent version isn't currently rolled out in Roo. In fact, I don't think there are plans (as far as I know) to upgrade Spring Javascript to 1.7.x, nor to update Roo. I will check with the Roo team to see what they are planning here.

People coding in Javascript shouldn't try to hide it. I'm not yet a fan of CoffeeScript or other frameworks that hide those things from you, because I think Javascript is such as quirky animal that dealing with it directly is probably better than not dealing with it, or working behind a veil.

Dojo is in transition

Because it was old, I decided to upgrade to Dojo 1.7. I gave up after a day because Dojo is transitioning to a new, bitchin' ARM (dynamic loading module system) that looks to be the bee's knees. Keep your eye on Dojo once this gets fully documented. They have curation, they have a consistent movement forward, active IRC channel, etc., and so I think they will really have a nice product here. However, I can't understand it, know the 1.6 and below model, and the documentation is not updated completely. So I was swimming in it.

We need a super-simple ui mechanism for Roo apps

I'm sorry, but I'm a minimalist. If I don't need it, it's outta here. And the view technologies in Roo should be pluggable. I think we should be able to do commands like:

roo> web mvc riatags add --toolkit dojo|extJS|jqueryUI|jqueryMobile

Scaffolding is in the way

I also think the scaffolding in Roo should be forward-only. Let's face it, how many times do you really keep the scaffolded UI on? For an admin tool, sure. But for anything commercial, it just takes too much to unwind it.

In addition, I think the messages/properties localization should be optional, or at least 100% transparent to me. In other words, the div id is the full div id, the message id is the full message id, period. It NEEDS to be simpler.

Finally, if I decide to modify my view resolution system, move to straight JSPs and ignore any bi-directional sync, I want Roo to keep hands off. I'll have to post a JIRA on this, but I think I ran into trouble where Roo adjusted my webmvc-config.xml file settings if I removed a few things once I tried to scaffold again. No biggie as I'm sure this isn't something planned on, but I think the bi-directionalness is great in the code layer, but not in the UI.

You seem tired

It's gonna be dawn soon and I'm thinking too much. I am really keen on moving Roo forward and working with the team to help set the agenda for Roo 1.3. All of this is adjustable by writing Roo add-ons and some minor adjustments to the current ones. And Roo saved me many hours on this project so far, and it will continue to do so.

So, big mouth, what have YOU been doing?

If you look in the GitHub repository, you'll see that I'm building a (currently AWFUL LOOKING) Dojo interface at /quizinator/admin/moderator. That controller does Ajax JSON request handling, and the index view is a small tab-container Dojo application.

More on this when I've had sleep and have implemented more. I may keep the actual quiz-taker UI in Spring Web Flow, and use Dojo for some Ajax there. But I like having a moderator tool that is a true Javascript client.

Monday
Feb272012

Quizzo in Roo case of the Mondays. Or, how you can be a JPA doofus 

This morning I took a look at my schema, and started to cry. Well, not really, but in that way people say LOL, I say COL. Here was my original schema (click to view the picture in full resolution):

Wait, this guy knows JPA? Sure he does!

Now, I know some of you have my back here. You say, "look, JPA can be confusing, you have to work with it." The thing is, I wrote a bloody chapter on JPA relationships, I teach JPA, my head just wasn't in the game, OK?

Just kidding. You know by now I'm razzing you all...

Anyhoo, I didn't bother taking any time to pay attention to my relationships (sounds like somebody's going to have cold soup for dinner). Turns out, I was abusing my @JoinColumn and mappedBy settings.

How to do a bi-directional one-to-many relationship

Do it up, Rimp. Here's how. First off, you need to define your one-sided entity and allow it to contain your Set (don't get me started about alternative options for collection types, that'll take us all day):

@RooJavaBean
@RooToString
@RooJpaEntity
public class Quiz {

    @NotNull
    @Size(max = 200)
    private String title;

    @NotNull
    @Size(max = 500)
    private String description;

    @OneToMany(mappedBy = "quiz",
        cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private Set<Question> questions = new HashSet<Question>();

}

Now, I know we're all adults in here, so that's why I put the harder stuff in the cabinet. You see, there are several key items of critical information here:

  • The collection is of type Set, and I'm creating a prototype (for new entities before I save them) of the real type of HashSet. Don't assume they will be HashSet instances when you fetch them again, they likely could be proxies that hydrate when you touch them (wear coding gloves).
  • I've decided to use the cascade option to tell JPA to cascade changes to the questions if I persist or update (merge) the quiz.
  • The mappedBy element is all-important. This tells us that the property pointing back to our Quiz instance in the class named Question will be called quiz. This establishes what side owns the relationship. As one of my students once said, "if you see mappedBy, it means this class does NOT own the relationship." Good rule to live by.

Whew! I'm feeling weak and dizzy. A lot of information hiding in there. Let's look at the Question class for the other side of this thing:

@RooJavaBean
@RooToString
@RooJpaEntity
public class Question {
  @ManyToOne
  @JoinColumn(name = "quiz_id")
  private Quiz quiz;
}

Wow, that's it??? Huh. Ok, well erm let's give this a shake. This class is in charge of the relationship, meaning that if it is touched, it will handle the insert or update of the foreign key. So:

  • The quiz variable name matches the mappedBy element in the Quiz table. Think of this as the role of the relationship. You may use the same table twice with different roles (think sourceAccount, destinationAccount and you get the idea. They would each have different @OneToMany relationships with different mappedBy elements, thereby different roles and variables.
  • The foreign key column that handles the database relationship is called quiz_id, and so we'll get a table called Question with a foreign key in it called quiz_id

Easy, peasy! Now, if you look at the relationship between Question and Quiz in the image above, it looks like there are three tables. But in the one below, the relationships are all simplified. That's because I paid attention to @JoinColumn and mappedBy. Click the image to see the full copy:

Mmmm... Low fat data models. Delicious and 1/2 the tables of your normal schema.

What else did I change recently?

I also got the state machine 99% working, with just a hitch on the test that determines whether the quiz is over or not. I'll work on that one tonight, now that I can actually understand my data model without getting sick to my stomach.

I moved the QuizRunState tracking state into memory, as it was failing me. Oh, one more thing - don't assume that IntelliJ catches Java Language assert statements. I was guarding my code with assertions to catch any invalid states in the state machine. Turns out, Maven turns on assertion checking when testing but IntelliJ does not. I'm not talking about JUnit assertions, but the Java System assertion language statement, such as I use in this fragment of QuizRunStateMachineInMemory:


  @Transactional
  public void startQuiz() {
    assert (runState == QuizRunState.NOT_STARTED);
    runState = QuizRunState.IN_PROGRESS;
  }

Oh, it burns us baggins! To fix this, you edit your JUnit runner and add the -ea -esa flags to your vm settings. And, ladies and gentlemen, that was the reason I was getting errors in my Maven code that weren't showing up in IntelliJ. Just sayin'

See ya tomorrow (or maybe later tonight).