You might not know that the order of static imports and ordinary imports is crucial. I stumbled upon a code snippet using a static import from a static inner class, during some codes research for a work project. Trying out that code ends up with a compiler error, saying that a standard class from the JDK was not found.
Kategorie: Dev Note
This little code snippet transforms the code formatter XML description file into a properties structure which could be applied to the JDT properties later on.
def initializeFormatter() { def formatterDefinitions = new XmlSlurper.parse("$rootDir/misc/codeformatter.xml") assert formatterDefinitions instanceof GPathResult def Properties props = new Properties() formatterDefinitions.'**'.findAll{ node -> node.name() == 'setting' }*.each { n -> props.put(n.@id.text(), n.@value.text() } return props }
Gradles project model provides a consistent way of expressing a version of an artifact. The following task uses the version number and makes it accessible to application code. Furthermore it adds the number of the build given by the Jenkins CI server.
/** * Read the version number from gradle (multi-) project definition * and add the build number from Jenkins-ci if available, otherwise use "IDE" */ task injectVersion << { def lineSep = System.getProperty("line.separator", "n") def file = file("$sourceSets.main.output.resourcesDir/version.properties") file.newWriter().withWriter { w -> w << "version=" << rootProject.version << lineSep w << "buildNumber=" << (System.getenv("BUILD_NUMBER") as String ?: "IDE") << lineSep } } // the inject version task requires the output folders to be already created injectVersion.mustRunAfter processResources // the version properties file have to be added to the classpath resource classes.dependsOn injectVersion
It is worth to notice that the inject version task relies on the existence of the resource output directory from the „main“ source set. Therefore it is not allowed to run before the processResources
has been completed and it depends on the classes
task.
Someone might consider extending the processResources
task putting the version.properties
file creation into the doLast
step like:
processResources.doLast { def lineSep = System.getProperty("line.separator", "n") def file = file("$sourceSets.main.output.resourcesDir/version.properties") file.newWriter().withWriter { w -> w << "version=" << rootProject.version << lineSep w << "buildNumber=" << (System.getenv("BUILD_NUMBER") as String ?: "IDE") << lineSep } }
This works well except for changing numbers without cleaning, because gradle could not decide whether the build number has changed or is still unchanged during its configuration phase.
References
- Get the build number from Jenkins – http://blog.jensdriller.com/how-to-include-jenkins-ci-build-number-in-android-apk-name/
Automated provisioning of the required build environment is one of the great promises by gradle. Using gradle wrapper allows the rapid workspace setup for a new developer or on a new machine.
In organizations there are sometimes restrictions in accessing public networks and it local hosting becomes inevitable. The actual example is based on the idea hosting the gradle distribution inside the local document management system which is accessible using https only.
# gradle-wrapper.properties distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https://provisioning-url/gradle-2.2-bin.zip
Unfortunately the server identity is assured by a self-signed resp. signed by a local authority certificate. Running the gradle wrapper screws up yielding the following exception:
<br />> gradlew tasks Downloading https://provisioning-url/gradle-2.2-bin.zip Exception in thread "main" java.lang.RuntimeException: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at org.gradle.wrapper.ExclusiveFileAccessManager.access(ExclusiveFileAccessManager.java:78) at org.gradle.wrapper.Install.createDist(Install.java:44) at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:126) at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:58) Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1884) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:270) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1341) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868) at sun.security.ssl.Handshaker.process_record(Handshaker.java:804) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323) at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563) at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java :185) at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1300) at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254) at org.gradle.wrapper.Download.downloadInternal(Download.java:56) at org.gradle.wrapper.Download.download(Download.java:42) at org.gradle.wrapper.Install$1.call(Install.java:57) at org.gradle.wrapper.Install$1.call(Install.java:44) at org.gradle.wrapper.ExclusiveFileAccessManager.access(ExclusiveFileAccessManager.java:65) ... 3 more Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385) at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292) at sun.security.validator.Validator.validate(Validator.java:260) at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:326) at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:231) at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1323) ... 19 more Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196) at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268) at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380) ... 25 more
The problem is that the HTTPS connection could not be validated because there is no trusted certificate for the provisioning url available.
The solution is to enhance the truststore with the certificate or the authority used in the provisioning url:
#create or copy an existing truststore eq. form jdk > cp $JAVA_HOME/jre/lib/security/cacerts certs.jks # import your certifiact into certs.jks > keytool -importcert -file self-signed.pem -keystore certs.jks
and tell gradlew to use this truststore instead of the original one. Gradles behavior can be adjusted by modifying the gradle.properties
file in the root directory of your gradle project (for more information see „The Build Environment“ from the user guide).
# gradle.properties systemProp.javax.net.ssl.trustStore=certs.jks # could set password as well # javax.net.ssl.trustStorePassword=changeit
Calling gradlew
again should kick off downloading the gradle distribution and running your tasks like a charm.
Update 27/10/2016
Changed password property to match the truststore. Thanks to Thomas for his advice.
Sometimes it is useful to set up a SoapUI test for simulating different usage scenarios randomly. The following solution provides a random selection from prepared test steps resulting in a different behavior of the tested service.
„Dev Notes“ is a small column about practical hints on certain problems or solutions taken from real world applications.
AngularJS is a great framework simplifying the development of JavaScript applications. The following example shows how to setup a global error handler to notify the user about the applications state.
To benefit from angulars super powers the global fault handler part visible to the user is encapsulated into an angular directive which is an easy but powerful way to enhance the HTML tag cloud with your own components. Building the handler involves roughly the following steps:
Note: For those who are not fluent in CoffeeScript the code can be ‚compiled‘ to JavaScript on the CoffeeScript homepage using the ‚Try CoffeeScript‘ tab.
- Add global fault handler and clear method
app.run ($rootScope, $log) -> ### # fault handler ### $rootScope.faultHandler = (data) -> $log.debug "[faultHandler] error data[#{data}]" # handle and process error data here # assign error message to global fault message $rootScope = "ERROR: #{data}" ### # clear fault ### $rootScope.clearFault = () -> $log.debug "[faultHandler] clearing fault[#{$rootScope.errorMessage}]" $rootScope.errorMessage = undefined
- Create custom tag to include the error handler
'use strict' angular.module('myApp') .directive('errorMessages', () -> template: "<div class='alert alert-danger' data-ng-show='errorMessage'><strong>Achtung: </strong><span data-ng-bind='errorMessage'></span></div>" restrict: 'E' )
- Refer to fault handler
'use strict' angular.module('myApp') .controller 'UserprofilCtrl', ($scope, $rootScope, $log, UserProfilService) -> $scope.profil = $rootScope.user # query userprofile by UID result = UserProfilService.get({id: $scope.profil.uid}) result.$promise.then (profil) -> $scope.profil = profil $rootScope.clearFault() .catch $rootScope.faultHandler
- Use it
<!-- include the following place holder tag into your page --> <x-error-messages></x-error-messages>