XSD schema validation – how to deal with a repeating group that also contains elements that can appear in any order?

Below is the XML that I need to validate. <Trustee> node is a repeating group and <TrustNameOptions> element can appear in any order, before or after <Trustee>
<Trust>
    <ABN>123456</ABN>
    <TrustName>Trust name</TrustName>
    <TrustNameOptions/>
    <Trustee>
        <TrusteeType>Individual</TrusteeType>
        <IndividualTrustee>
            <FirstName>John</FirstName>
        </IndividualTrustee>
    </Trustee>
    <Trustee>
        <TrusteeType>Company</TrusteeType>
        <CompanyTrustee>
            <Name>Company name</Name>
        </CompanyTrustee>
    </Trustee>
</Trust>
So how do I validate the XML? <xsd:all> allows elements to appear in any order, but it only allows maxOccurs=”1″ for <Trustee> (not “unbounded” which it needs to be).
<!-- Doesn't work -->
<xsd:element name="Trust">
  <xsd:complexType>
      <xsd:all>
          <xsd:element name="ABN" type="abn"/>
          <xsd:element name="TrustName" type="entityNameSafeString"/>
          <xsd:element name="TrustNameOptions" type="entityNameSafeString" minOccurs="0"/>
          <xsd:element name="Trustee" type="trusteeType" minOccurs="0" maxOccurs="1"/>
      </xsd:all>
  </xsd:complexType>
</xsd:element>
Using <xsd:sequence> allows maxOccurs=”unbounded” for <Trustee> but it means the elements have to appear in sequence (defined order), so having <TrustNameOptions> appear in any order doesn’t work.
<!-- Doesn't work -->
<xsd:element name="Trust">
  <xsd:complexType>
      <xsd:sequence>
          <xsd:element name="ABN" type="abn"/>
          <xsd:element name="TrustName" type="entityNameSafeString"/>
          <xsd:element name="TrustNameOptions" type="entityNameSafeString" minOccurs="0"/>
          <xsd:element name="Trustee" type="trusteeType" minOccurs="0" maxOccurs="unbounded"/>
      </xsd:sequence>
  </xsd:complexType>
</xsd:element>
Solution = use <xsd:choice maxOccurs=”unbounded”>. This worked, it allowed me to combine my requirements. Allows elements to appear in any order and to also have a repeating group <Trustee> (maxOccurs=”unbounded”). I found this solution on stack overflow
<!-- Works -->
<xsd:element name="Trust">
  <xsd:complexType>
      <xsd:choice maxOccurs="unbounded">
          <xsd:element name="ABN" type="abn"/>
          <xsd:element name="TrustName" type="entityNameSafeString"/>
          <xsd:element name="TrustNameOptions" type="entityNameSafeString" minOccurs="0"/>
          <xsd:element name="Trustee" type="trusteeType" minOccurs="0" maxOccurs="unbounded"/>
      </xsd:choice>
  </xsd:complexType>
</xsd:element>
However, my team wasn’t very comfortable with this solution. We decided to try and make <TrustNameOptions> appear in order (above <Trustee>). Then we could simply use <xsd:sequence> like normal. Failing this, we decided it was maybe ok to use <xsd:choice> as long as our downstream system which used XJC (XML schema binding to Java classes) worked, and could handle the <xsd:choice maxOccurs=”unbounded”>. I ended up getting things to appear in order, so we went with <xsd:sequence>

Java Joda time – the danger of time zone conversion

At work, I wrote some time zone conversion code in Java and was surprised to learn of the dangers of using Joda time library. It throws an exception during 1 hour ‘error window’ when clocks are moved forward 1 hour eg Daylight Savings Start (DST). Our legacy code used Joda time library.

Lessons learnt

  1. Avoid time zone conversion code where possible. If need to convert time, use java.time rather than joda time
  2. Use LocalDateTime if possible
  3. Or use UTC if LocalDateTime not possible

Joda Time (version 2.10.6)

Daylight savings end (Sun 5 Apr 2020) – 3am clock moves back 1 hour was ok
Daylight savings start (Sun 4 Oct 2020) – 2am clock moves forward 1 hour has 1 hour error window where it throws an exception
SYD timeJoda time SYDJoda time UTCHours diff
04/10/20 01:59:5904/10/20 01:59:5903/10/20 15:59:5910
04/10/20 02:00:0004/10/20 02:00:00Illegal instant due to (see below)n/a
04/10/20 02:59:5904/10/20 02:59:59Illegal instant due to (see below)n/a
04/10/20 03:00:0004/10/20 03:00:0003/10/20 16:00:0011
Exception = Illegal instant due to time zone offset transition (daylight savings time ‘gap‘): 2020-10-04T02:00:00.000 (Australia/Sydney)

Java Time

Luckily the java.time library available from Java 8 works as expected, correctly resolving the ‘error window’ and not throwing any exceptions
SYD timeJava time SYDJava time UTCHours diff
04/10/20 01:59:5904/10/20 01:59:5903/10/20 15:59:5910
04/10/20 02:00:0004/10/20 03:00:0003/10/20 16:00:0011
04/10/20 02:59:5904/10/20 03:59:5903/10/20 16:59:5911
04/10/20 03:00:0004/10/20 03:00:0003/10/20 16:00:0011
04/10/20 03:59:5904/10/20 03:59:5903/10/20 16:59:5911

Joda Time test code

I discovered this issue when writing some tests
@Test
void convertSydTimeToUtc_daylightSavingsStarts_beforeCutoff() {
    LocalDateTime localDateTime = new LocalDateTime(2020, 10, 4, 1, 59, 59);
    DateTime sydDateTime = localDateTime.toDateTime(sydneyTimeZone);

    DateTime utcDateTime = TimezoneConverter.convertSydToUtc(sydDateTime);

    assertThat(utcDateTime.toString()).isEqualTo("2020-10-03T15:59:59.000Z");
    int offsetInMillis = sydneyTimeZone.getOffset(sydDateTime.toInstant());
    int offsetInHours = offsetInMillis / HOURS_IN_MILLIS;
    assertThat(offsetInHours).isEqualTo(10);
}

@Test
void daylightSavingsStart_forward1Hour_throwsException_duringDeadWindowStart() {
    LocalDateTime localDateTime = new LocalDateTime(2020, 10, 4, 2, 0, 0);

    assertThatThrownBy(() -> localDateTime.toDateTime(sydneyTimeZone))
            .isInstanceOf(IllegalInstantException.class)
            .hasMessageContaining("Illegal instant due to time zone offset transition (daylight savings time 'gap')");
}

Java time test code

@Test
void convertSydTimeToUtc_daylightSavingsStarts_beforeCutoff() {
    LocalDateTime localDateTime = LocalDateTime.of(2020, 10, 4, 1, 59, 59);
    ZonedDateTime sydDateTime = localDateTime.atZone(ZoneId.of("Australia/Sydney"));

    ZonedDateTime utcDateTime = TimezoneConverter.convertSydToUtc(sydDateTime);

    assertThat(utcDateTime).isEqualTo("2020-10-03T15:59:59Z[UTC]"); // 2020-10-03T16:00Z[UTC]
    assertThat(sydDateTime.getOffset().toString()).isEqualTo("+10:00");
}

@Test
void convertSydTimeToUtc_daylightSavingsStarts_afterCutoff() {
    LocalDateTime localDateTime = LocalDateTime.of(2020, 10, 4, 2, 0, 0);
    ZonedDateTime sydDateTime = localDateTime.atZone(ZoneId.of("Australia/Sydney"));

    ZonedDateTime utcDateTime = TimezoneConverter.convertSydToUtc(sydDateTime);

    assertThat(utcDateTime).isEqualTo("2020-10-03T16:00Z[UTC]");  // 2020-10-03T16:00Z[UTC]
    assertThat(sydDateTime.getOffset().toString()).isEqualTo("+11:00");
}

Global Coronavirus charts

A colleague introduced me to this great dashboard for coronavirus. Then I discovered that github had a daily repository of this data, so why not build a web app that could chart it daily? Previously I was interested in ~ 10 countries and taking ~ 10 mins / day to keep the charts updated.

How to access?

https://jasonsoo.com:9000

What do you get?

You already got a great global view from the covid dashboard, but this app allows you to
  1. View the various charts individually or combined (eg active, recovered)
  2. Easily compare 2 countries side by side
I hope you’re all keeping save and this app makes it easy for you to track countries that you’re interested in.

How to learn Java programming?

Being a Java engineer, I’ve often been asked what’s a good way of learning Java programming? Also, from a career development perspective, I was thinking how I would go about improving my Java and broader programming skills.

What’s the objective?

I think its useful to define some objectives to help target the learning. I think the ultimate goal would be to find a Java programming job. But along the way, it’d be good to develop solid Java skills.

Initial

  1. Learn Core java and increase proficiency
  2. Be confident thinking & programming in Java
  3. Know later versions of Java, eg Java 11, latest Long Term Support (LTS) version
  4. Get to an Intermediate level of Java

Job focussed

  1. Be familiar with Java Test Driven Development (TDD), for improved code quality. Learn about unit tests, integration tests, etc.
  2. Learn a framework (eg Spring) to see how frameworks speed up programming
  3. Learn how to use a build tool (eg Gradle) to easier manage dependencies and build cycle
  4. Write an App to apply knowledge. Put on github for public viewing
  5. Write clean code
  6. Get a Java job

Whats the approach?

  1. Use a good Integrated Development Environment (IDE) and setup your programming environment
    • I like Intellij
    • make sure you can write a ‘Hello World‘ program
  2. Depending on your level: start by reading a good book or doing a good course / watch video
    • start with fundamentals (core java), then syntax, then idioms
    • make sure the book / course has good exercises for each section so you can test your understanding
    • don’t worry about frameworks initially. Start learning the language
  3. As your knowledge grows, keep on coding and thinking in that language
  4. Try to get to an Intermediate level by reading ‘Effective Java‘ and learning Java concurrency
  5. Learn about Java Test Driven Development (TDD). I appreciate colleagues that write tests to improve code quality
  6. Learn a framework (eg Spring)
  7. Write a Spring Boot Web App in TDD fashion
  8. Do Java tests and practice interview questions
  9. Apply for Java jobs (good luck!)
  10. Contribute to Open Source projects and help the community

Beginner to Intermediate books

  • Java: A Step-by-Step Guide for Absolute Beginners (Bell, 2019)
  • Beginning Programming with Java For Dummies 5th Ed (Burd, 2017)
  • Learn Java in One Day and Learn It Well (Chan, 2016)
  • Thinking in Java 4th Ed (Eckel, 2006)
  • Core Java Volume 1 – Fundamentals, 11th Ed (Horstmann, 2018): updated to Java SE 9, 10, 11
  • Core Java SE 9 for the Impatient 2nd Ed (Horstmann, 2017)
  • Head First Java 2nd Ed (Sierra, Bates, 2005): good but dated, only up to Java SE 5
  • Test Driven: TDD and Acceptance TDD for Java Developers (Koskela, 2007)

Intermediate to Advance books

  • Effective Java 3rd Ed (Bloch, 2017): updated to Java SE 7, 8, 9
  • Java Concurrency in Practise 1st Ed (Goetz, 2006)
  • Clean Code: A Handbook of Agile Software Craftsmanship 1st Ed (Martin, 2008)
  • Java Performance: The Definitive Guide 1st Ed (Oaks, 2014): garbage collection, JVM, performance tuning
  • Reactive Programming with RxJava (Nurkiewicz, 2016)

What is the Java Programming Language?

Java is a programming language that is strongly typed, Object Oriented and imperative. It has a philosophy of Write Once, Run Anywhere (WORA).

Principles

  1. It must be simple, object-oriented, and familiar.
  2. It must be robust and secure.
  3. It must be architecture-neutral and portable.
  4. It must execute with high performance.
  5. It must be interpreted, threaded, and dynamic.

Pros

  • robust & standard for enterprise computing
  • good performance, multi threaded
  • fewer security risks
  • platform independent (WORA)
  • OO programming (improved over procedural programming)
  • very popular: lots of java engineers, and lots of java jobs
  • big and mature community, lots of open source libraries

Cons

  • paid commercial license
  • large memory footprint
  • verbose (compared to Kotlin)
  • no functional programming
  • desktop is far from native look & feel

Linux VirtualBox: how to expand screen size when resizing

This is for a computer running Linux (in this case Ubuntu 19.04) installing a VirtualBox Linux operating system. The default Display setting (Graphics Controller: VMSVGA) doesn’t expand the screen size when re-sizing.
Screen doesn’t expand when re-sized
Go to Settings -> Display -> Graphics Controller = VBoxSVGA. It will resize correctly when expanded.
Screen expands when re-sized
Correct setting (VBoxSVGA) allowing display expansion
Default incorrect setting = VMSVGA which doesn’t allow display expansion
FYI – I recall the solution is different for Mac. Will post the Mac solutions soon.