Recently the Startable#START
field (public static final, by virtue of
being part of a public interface) was modified. This caused problems
when using applications linked against Brooklyn. In particular, if
Brooklyn was built after the change without issuing an 'mvn clean'
command then classes that merely referenced this static field did not
get re-compiled, and their bytecode (including the old field value) was
simply included in generated Jar files.
When deploying a YAML file, a call is made to invoke the 'start'
effector, referenced as Startable#START
inside ApplicationResource
.
This began to fail for me, with the exception indicating that the
START
field was not found.
This is because references to final fields are treated as constants and the values are included in the referencing class at compile time. So, if the value changes in the declaring (API) class, this is not propagated. See the JLS, section 13.4.8, excerpted below:
If a field is a constant variable (§4.12.4), then deleting the keyword final or changing its value will not break compatibility with pre-existing binaries by causing them not to run, but they will not see any new value for the usage of the field unless they are recompiled. This is true even if the usage itself is not a compile-time constant expression (§15.28).
This result is a side-effect of the decision to support conditional compilation, as discussed at the end of §14.21.
As I mentioned, the obvious and simple fix is to recompile all the things. This is a nuisance, and end users of our APIs will still be affected when they try to load a Jar with a compiled entity or application linked against the pre-change Brooklyn, into the latest Brooklyn.
It's something to be aware of if your applications start failing or behaving oddly because old configuration values are being used. The place this will trip people up most often is a situation where a third-party application sets configuration like this:
Entity e = addChild(EntitySpec.create(Something.class)
.configure(Something.SENSOR_KEY, SomethingElse.SENSOR));
Then, in Brooklyn, we change the definition of SENSOR in SomethingElse. The entity will still be referencing the old sensor details, even if we rebuild (without a 'clean') using Maven. And you may not even know there have been Brooklyn changes, an updated -SNAPSHOT build deployed to SonaType could be being used when you build your application locally.
But, I'm not really sure if there's anything much we can do to mitigate
this. We use static final constants heavily for ConfigKey
and
AttributeSensor
definitions, which isn't going to stop. And, of
course, the problem goes away when you next remember to do an 'mvn clean
install' often enough.