A couple weeks ago I came across EA Async, which transforms Java methods containing "await" calls into a series of asynchronous, non-blocking tasks. This makes it easier to write nice asynchronous code for the JVM. EA Async can perform the transformation at runtime via a Java agent, at build time via a command-line utility, or at build time via a Maven plugin. Using a build system plugin integrates the transformation into the normal development workflow, which is very convenient. Of course, since there's only a Maven plugin, only users of the Maven build system got this benefit.
I like Gradle, another very widely used build system. So yesterday and today I went ahead with writing a Gradle plugin for EA Async. It was a little tricky to build a Gradle plugin with their Maven project, but once I got it compiling it was fairly straightforward thanks to my work on other Gradle plugins. There was a subtlety in taking advantage of the transformer's support for custom CompletionStage implementations. Their class files needed to be accessible through the classloader passed to the transformer, so I had to involve the compilation task's classpath and its output directory to make sure the CompletionStage implementations in the target project were recognized.
I made a pull request today which was merged. The plugin will probably be published in the next EA Async release.
Various technical articles, IT-related tutorials, software information, and development journals
Thursday, January 9, 2020
Wednesday, January 8, 2020
Building Gradle plugins with Maven
Today I started writing a Gradle plugin module for a project that uses Maven as its build system. I know it's possible, with some fiddling, to involve a Gradle build in a Maven setup, but this project is managed by someone else and I wanted to stay with their preferred technology as much as possible.
Since Gradle plugins are ultimately just JARs, it's possible to compile them with Maven. Of course, this loses Gradle's convenient facilitation of writing Gradle plugins. Specifically, you need to add various dependencies yourself rather than just using gradleApi(). These <dependency>s generally look like:
<groupId>org.gradle</groupId>
<artifactId>gradle-something</artifactId>
<version>5.6.4</version>
<scope>provided</scope>
I'm currently using version 5.6.4 because it's the latest version of the Gradle 5 series, which supported by Android Studio and used by a lot of projects. The "provided" scope makes it used only for compilation, never bundled with the plugin. You may also need a reference to Groovy.
The various types are spread across quite a few artifacts. For a pretty straightforward plugin (doing some extra stuff with the results of Java compilation), I needed dependencies on gradle-core, gradle-core-api, gradle-base-services, gradle-model-core, gradle-language-jvm, gradle-language-java, gradle-platform-jvm, gradle-plugins, and gradle-tooling-api. To determine which artifact provides a class the compiler can't find, you can search the Gradle monorepository.
For adding the plugin metadata, the properties file can go in the same place under resources/META-INF that it would with a Gradle build.
Since Gradle plugins are ultimately just JARs, it's possible to compile them with Maven. Of course, this loses Gradle's convenient facilitation of writing Gradle plugins. Specifically, you need to add various dependencies yourself rather than just using gradleApi(). These <dependency>s generally look like:
<groupId>org.gradle</groupId>
<artifactId>gradle-something</artifactId>
<version>5.6.4</version>
<scope>provided</scope>
I'm currently using version 5.6.4 because it's the latest version of the Gradle 5 series, which supported by Android Studio and used by a lot of projects. The "provided" scope makes it used only for compilation, never bundled with the plugin. You may also need a reference to Groovy.
The various types are spread across quite a few artifacts. For a pretty straightforward plugin (doing some extra stuff with the results of Java compilation), I needed dependencies on gradle-core, gradle-core-api, gradle-base-services, gradle-model-core, gradle-language-jvm, gradle-language-java, gradle-platform-jvm, gradle-plugins, and gradle-tooling-api. To determine which artifact provides a class the compiler can't find, you can search the Gradle monorepository.
For adding the plugin metadata, the properties file can go in the same place under resources/META-INF that it would with a Gradle build.
Tuesday, January 7, 2020
Policy Plus - More list UI fixes
The list policy element might be the most finicky part of Policy Plus. Today I received an issue report from a user stating that adding entries to a list in a certain policy failed to make the policy Enabled. That specific policy had no affected Registry entries of its own, only a key populated by the list element. Since the list element was set to clear all existing values, it was always interpreted as evidence in favor of the Disabled policy state. I corrected this by also checking for list entries, which are evidence in favor of the Enabled state.
While investigating that specific policy, I found a problem in the Element Inspector. Even though the list element had a prefix attribute (albeit an empty one), the inspector said "no prefix." I corrected the conditional.
While investigating that specific policy, I found a problem in the Element Inspector. Even though the list element had a prefix attribute (albeit an empty one), the inspector said "no prefix." I corrected the conditional.
Monday, January 6, 2020
Windows RAID will be extremely slow when resynchronizing
A while ago I was called in to look at a server that was performing very slowly. Disk-bound operations were primarily affected. This server uses Windows RAID for redundancy and the mirror was in the process of resynchronizing. (It had recently lost power unexpectedly.) I suspect it was checking the entire volume for consistency, which uses a lot of I/O and slows down everything else trying to use the disk.
Sunday, January 5, 2020
Policy Plus - REG file tolerance
I got a report from a Policy Plus user that the Import REG feature could not handle comments. This is true; I wrote the REG parser for exactly the format emitted by the Registry Editor. Even whitespace differences could cause parse failures. So to make it easier to manually write REG files used by Policy Plus, I adjusted that parser. Comments and extra blank lines are now allowed.
I also happened to notice that searching for a certain policy made the search dialog say it found a hit but not actually display a result. Apparently I had only put the list-updating code in the progress-update, not completion, handler. So up to 19 policies could never be shown in the search results. I fixed that with a tweak to the search dialog.
I also happened to notice that searching for a certain policy made the search dialog say it found a hit but not actually display a result. Apparently I had only put the list-updating code in the progress-update, not completion, handler. So up to 19 policies could never be shown in the search results. I fixed that with a tweak to the search dialog.
Tuesday, December 31, 2019
Parceling and unparceling is not necessarily deep cloning
Serializing something to a temporary buffer then deserializing it is often an easy way to duplicate an object that supports serialization. Today I was trying to make independent copies of a handful of different Parcelable classes, so I tried writing a general function to parcel them then read them back out. I ran into trouble with testing because my Robolectric shadows of IBinder classes the parcelables referred to contributed state that did not get written to the parcel. However, I realized another problem: parcels can transfer active IBinder objects. These will be reconstituted into proxies that call into the original object, foiling the plan of creating a deep, independent copy for an arbitrary Parcelable.
Monday, December 30, 2019
Putting an array on the pipeline with the unary comma operator
When output onto the pipeline, PowerShell arrays tend to explode into individual pipeline items. I used to deal with this by passing arrays as parameters instead. Recently, though, I heard about the unary comma operator. Placing a single comma before any value, including an array, produces a single-element array containing the value. When that explodes onto the pipeline, it releases the original array.
Subscribe to:
Posts (Atom)