Studio & Gosu

Every Guidewire developer lives in two things: Guidewire Studio, where configuration is edited and the server is run, and Gosu, the language that ties it all together. If you know Java, Gosu will feel familiar within a day — but a few features are worth learning properly.

Guidewire Studio

Studio is an IntelliJ-based IDE that understands Guidewire's file types. From it you:

  • edit entities, typelists, PCF screens, rules, Gosu classes, display keys and plugin registries with dedicated editors,
  • run and debug the application server locally, with breakpoints in Gosu,
  • try snippets in the Gosu scratchpad against a running server,
  • run GUnit tests (Guidewire's test framework on top of JUnit).

Builds and server runs are driven by the project's build tool (Gradle in current releases), so the same tasks run on a developer laptop and in CI.

Base vs configuration

The product ships with base configuration you must not edit. Your work goes in the configuration layer on top:

base Guidewire's shipped config (read-only) ↑ overridden by configuration your entities, typelists, PCFs, rules, Gosu, plugins
  • To change a base file, Studio copies it into the configuration layer and you edit the copy. That copy is now yours to merge on every upgrade, so do it sparingly.
  • Prefer additive changes: extensions of base entities and typelists (module 14), new PCF files, new classes, new rules.
  • Name everything you add with a project suffix — _Ext is the common convention — so it never collides with future base names.
Upgrade cost

Every base file you copy and modify is a merge conflict waiting for the next release. On Guidewire Cloud, there are also platform rules about what may be changed at all. Ask "can I do this without touching base?" before every change.

Gosu basics

Gosu is statically typed, compiles to JVM bytecode and can call any Java library. Type inference keeps it short:

uses java.math.BigDecimal

var name = "Mette Hansen"            // String, inferred
var limit : BigDecimal = 25000bd     // explicit type, BigDecimal literal
var drivers = {"Mette", "Lars"}      // List<String>

function greet(who : String) : String {
  return "Hej, ${who}!"              // string template
}

print(greet(name))
  • Properties are first-class: claim.LossDate calls a getter; property get / property set define them.
  • Entities and typelists are Gosu types. Claim, Exposure and ClaimState.TC_OPEN are checked by the compiler, so a typo fails at compile time.
  • == compares values (like Java's equals); === compares identity.

Null safety

Gosu's property access is null-tolerant: if any step in claim.Policy.Insured.Name is null, the expression returns null instead of throwing. That's convenient, and also how bugs hide — a typo'd assumption silently becomes null. Method calls are not null-safe unless you use ?.:

var city = claim.LossLocation.City            // null if LossLocation is null
var upper = claim.Description?.toUpperCase()  // ?. needed for method calls
var label = claim.Description ?: "(none)"     // Elvis operator for defaults

Blocks and collections

Blocks are Gosu's lambdas. Combined with collection enhancements, they replace most loops:

var openExposures = claim.Exposures.where(\ e -> e.State == ExposureState.TC_OPEN)

var claimantNames = openExposures.map(\ e -> e.Claimant.DisplayName)

var hasInjury = claim.Exposures.hasMatch(\ e -> e.ExposureType == ExposureType.TC_BODILYINJURYDAMAGE)

var biggest = claim.Exposures.maxBy(\ e -> e.ReserveAmount)

Use typeis for type checks; inside the matching branch the variable is automatically narrowed:

if (incident typeis VehicleIncident) {
  print(incident.Vehicle.LicensePlate)   // no cast needed
}

Enhancements

An enhancement adds methods and properties to an existing type — including base entities — without modifying it. This is the main tool for keeping logic out of base files.

package acme.claim

uses gw.api.util.DateUtil

enhancement ClaimAgeEnhancement_Ext : entity.Claim {

  // Days since the loss happened; usable as claim.DaysSinceLoss_Ext everywhere
  property get DaysSinceLoss_Ext() : int {
    return DateUtil.daysBetween(this.LossDate, DateUtil.currentDate())
  }

  function isFastTrack_Ext() : boolean {
    return this.Exposures.Count == 1 and this.TotalIncurred_Ext < 5000
  }
}
Where logic lives

Keep business logic in Gosu classes and enhancements, and call them from rules and PCFs. Rules and screens then stay short, and the logic is testable with GUnit. Logic written inline in PCF attributes is hard to find and impossible to unit test.

Querying the database

The Query API builds type-safe SQL from Gosu:

uses gw.api.database.Query
uses gw.api.database.Relop
uses gw.api.util.DateUtil

var q = Query.make(Claim)
q.compare(Claim#State, Relop.Equals, ClaimState.TC_OPEN)
q.compare(Claim#LossDate, Relop.GreaterThan, DateUtil.currentDate().addDays(-30))

for (c in q.select()) {
  print("${c.ClaimNumber}: ${c.LossDate}")
}
  • Claim#State is a property reference, checked at compile time.
  • Results are loaded lazily; filter in the query, not in Gosu afterwards.
  • Query results are read-only. To change them, add each entity to a writable bundle (see module 02).