Hello World Tutorial
This hands-on tutorial will walk you through the steps of how to create a small application and explore it with some JUnit tests. This example is also used and extended in 3 other tutorials:
This is an introduction to Sculptor. A more extensive example is available in the Advanced Tutorial. If you would like to see something more exciting than running JUnit tests we can recommend the Developers Guide.
Before you start you must follow the instructions in the Installation Guide.
Table of Contents:
Part 1 - Setup Project
In this first part we will setup the project structure for Maven and Eclipse.
-
Use Sculptors Maven archetype with the following command (one line - indicated by the trailing
\
) to create a new project with Maven POM and file structure. You can change the groupId and artifactId if you like.mvn archetype:generate -DarchetypeGroupId=org.sculptorgenerator \ -DarchetypeArtifactId=sculptor-maven-archetype \ -DarchetypeVersion=3.1.0 \ -Dstandalone=true
The property
-Dstandalone=true
indicates that the project is not part of a Maven multi-module project and is not refering to a common parent projecthelloworld-parent
.Fill in groupId and artifactId:
Define value for groupId: : org.helloworld Define value for artifactId: : helloworld Define value for version: 1.0-SNAPSHOT: : Define value for package: org.helloworld: :
-
Open Eclipse and import the project via (via m2e Eclipse plugin) with “File > Import… > Existing Maven Projects”.
-
Create an Eclipse m2e launch configuration for executing Maven (e.g. with the goal
generate-sources
) from within Eclipse (right-clicking the project or Maven POM and selecting “Run as > Maven build…” from the context menu).To refresh the Eclipse workspace after Sculptors code generator created new code enable the option “Refresh > Refresh resources upon completion > The project containing the selected resource” in the launch configuration.
Part 2 - Generate Code
In this part we will write a Sculptor DSL file and generate code from it.
-
Open the file
model.btdesign
in the foldersrc/main/resources/
with Sculptor DSL editor. Add something like this to the design file:Application Universe { basePackage=org.helloworld Module planet { Service PlanetService { String sayHello(String planetName); protected findByExample => PlanetRepository.findByExample; } Entity Planet { String name key String message Repository PlanetRepository { findByExample; } } } }
Try the code completion, error highlight and outline view. It is a Module containing one Entity, with a Repository. The concepts are taken from Domain-Driven Design.
-
Run
mvn clean install
to generate code and build. The JUnit test will fail.! If the Maven build aborts with the error message
Executing 'dot' command failed
then the GraphViz package is not installed as described in the installation guide.If you run Maven from the command prompt you have to refresh the Eclipse workspace. If you start the Maven build from within Eclipse with the aforementioned m2e launch configuration then the workspace is refreshed automatically.
-
Look at the generated code. In
src/main/java
,src/main/resources
,src/test/java
andsrc/test/resources
folders the code is only generated once, and you can do manual changes. Insrc/main/generated/java
,src/main/generated/resources
,src/test/generated/java
andsrc/test/generated/resources
it is generated each time, i.e. don’t touch.
Part 3 - Fix Failing Test
In this step we will fix the failing JUnit test and add some hand written code.
-
Run
PlanetServiceTest
as JUnit Test. Red bar. Adjust the test methodtestSayHello
to something like this:public void testSayHello() throws Exception { String greeting = planetService.sayHello(getServiceContext(), "Earth"); assertEquals("Hello from Earth", greeting); }
-
HSQLDB is used as in memory database when running JUnit. Add test data in
src/test/resources/dbunit/PlanetServiceTest.xml
:<?xml version="1.0" encoding="UTF-8"?> <dataset> <PLANET id="1" name="Earth" message="Hello from Earth" LASTUPDATED="2006-12-08" LASTUPDATEDBY="dbunit" version="1" /> <PLANET id="2" name="Mars" message="Hello from Mars" LASTUPDATED="2006-12-08" LASTUPDATEDBY="dbunit" version="1" /> </dataset>
-
Run, still red, but another failure.
-
Implement method
sayHello
inPlanetServiceImpl
:public String sayHello(ServiceContext ctx, String planetName) { Planet planetExample = new Planet(planetName); List<Planet> foundPlanets = findByExample(ctx, planetExample); Planet planet = foundPlanets.get(0); return planet.getMessage(); }
-
Run. Green bar!
-
Add one more test method to test a failure scenario:
@Test public void testSayHelloError() throws Exception { try { planetService.sayHello(getServiceContext(), "pluto"); fail("Expected PlanetNotFoundException"); } catch (PlanetNotFoundException e) { // as expected } }
-
Add
throws PlanetNotFoundException
inmodel.btdesign
:String sayHello(String planetName) throws PlanetNotFoundException;
-
Regenerate with
mvn generate-sources -Dsculptor.generator.force=true
-
Add
throws PlanetNotFoundException
inPlanetServiceImpl.sayHello
. -
Fix the import of
PlanetNotFoundException
in the test class and run it, red bar. -
Fix the test. You need to adjust
sayHello
method:public String sayHello(ServiceContext ctx, String planetName) throws PlanetNotFoundException { Planet planetExample = new Planet(planetName); List<Planet> foundPlanets = findByExample(ctx, planetExample); if (foundPlanets.isEmpty()) { throw new PlanetNotFoundException("Didn't find any planet named " + planetName); } Planet planet = foundPlanets.get(0); return planet.getMessage(); }
-
Run. Green bar!
-
Run
mvn clean install
. Build success.
Tip
You can use mvn -o install
to speed up the builds (-o == offline).
To enforce regeneration you use mvn generate-sources -Dsculptor.generator.force=true