Micronaut/GORM Services

After another long evening of trying to get Micronaut to work as expected out of the box I’m beginning to think that the developers really don’t want anyone to use GORM!

Yesterday I was trying to convert one of my Grails apps to Micronaut. Moving the domain classes to entities was easy. Here is my Route entity (with uneccessary elements removed):

@Entity
class Route implements GormEntity<Route> {

    String grade
    Colour colour
    Date firstSeen
    Date removed

    static belongsTo = [line:Line]

}

Next we want a service. The pattern in latest versions of Grails and Micronaut is to define the service as an interface and then, optionally, provide an (abstract) implementation. Perhaps this is an underlying Hibernate pattern, see https://gorm.grails.org/latest/hibernate/manual/index.html#dataServices. A simple service might look something like this:

@Service(Route)
interface RouteService {

    List<Route> list() {}
    
    Route get(Serializable id) {}

}

This seemingly empty file gives hints to GORM to provide two methods. The first returns a list of all Routes, the second the Route with the given ID. In the controller then we can then write:

@Controller("/routes")
class RouteController {

    @Inject RouteService service

    @Get("/")
    def index() {
        return service.list()
    }

    @Get("/{id}")
    def get(Serializable id) {
         return service.get(id)
    }

}

At this point I expected to be able to run the app and be able to get a list of routes, or a single route, in JSON format. Instead, I got this exception:

Caused by: com.fasterxml.jackson.databind.JsonMappingException: 
could not initialize proxy [uk.co.channele.uclimb.domain.Colour#65] - no Session 
(through reference chain: java.util.ArrayList[0]->
uk.co.channele.uclimb.domain.Route["colour"]->
uk.co.channele.uclimb.domain.Colour$HibernateProxy$y3jqGOWU["name"])

So my evening of searching the interwebs began. Coming from a Grails background I tried creating a service with actual methods, but this didn’t work. (Also, I found that replacing @Inject with @Autowired didn’t work.)

I found various Jackson annotations that allowed me to exclude the colour field but excluding line wasn’t obvious. I found some stuff about making fetches “eager” and about marking items as transient, but none of these helped.

Finally I did find a solution and that was to add in a dependency so that Jackson with work with Hibernate:

implementation 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate5:2.10.2'

Why was this so difficult to find? Did I do something wrong when creating the application, there are lots of features available? I’d used the command:

mn create-app --features=hibernate-gorm,jdbc-hikari --lang=groovy uk.co.channele.uclimb

So I think it’s reasonable that I expected the application to render entities to JSON. Who knows?? As always, I hope that others might find this post useful.

Micronaut/GORM Unit Tests

I’ve recently revisited Micronaut as I need to re-write some old systems at work. Both of the systems are written in Grails, one provides an API, the other a very lightweight website. So Micronaut seems like the idea candidate. As a Grails developer I want to continue to use Groovy and GORM and both of these are supported.

I made a start on a few basic domain (Entity) classes with a few simple constraints. At this point I wanted to add some tests – yep, test driven development! However I ran in to problems getting the tests to run.

I created a test file following the same pattern as I would do in my Grails projects, but with what felt like common sense adaptations for Hibernate.

package uk.co.channele.mngorm

import io.micronaut.test.annotation.MicronautTest
import spock.lang.Specification

@MicronautTest
class AreaSpec extends Specification {

    void "test constraints"() {
        when: "an empty Area"
        def area = new Area()

        then: "not valid"
        !area.validate()

        when: "set the name"
        area.name = "name"

        then: "valid"
        area.validate()
    }
}

But when I tried to run the test with ./gradlew test I just got an exception:

org.springframework.dao.DataAccessResourceFailureException: Could not obtain current Hibernate Session; 
nested exception is org.hibernate.HibernateException: No Session found for current thread

This didn’t make sense, unit tests in Grails don’t expect the system to be running, mock objects are used instead. After a few late nights of searching/reading/cursing and trying many different variations I found this website https://guides.grails.org/grails-gorm-data-services/guide/index.html (notice no mention of Micronaut!) which gave me this solution:

package uk.co.channele.mngorm

import grails.gorm.transactions.Transactional
import io.micronaut.test.annotation.MicronautTest
import org.grails.orm.hibernate.HibernateDatastore
import org.springframework.transaction.PlatformTransactionManager
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification

@MicronautTest
@Transactional
class AreaSpec extends Specification {

    @Shared
    @AutoCleanup
    HibernateDatastore hibernateDatastore

    @Shared
    PlatformTransactionManager transactionManager

    void setupSpec() {
        hibernateDatastore = new HibernateDatastore(Area)
        transactionManager = hibernateDatastore.getTransactionManager()
    }

    void "test constraints"() {
        when: "an empty Area"
        def area = new Area()

        then: "not valid"
        !area.validate()

        when: "set the name"
        area.name = "name"

        then: "valid"
        area.validate()
    }
}

Which runs nicely and passes. Now I need to find a way to improve the Micronaut documentation so that potential users don’t suffer the same frustration as me!

Remove Gnome App Menu

I’ve been a Fedora/Gnome user for many years. I like to keep my desktop empty and the clutter to a minimum. So I don’t, for instance, have the window list at the bottom of the display.

In Fedora 31, the latest release as I write this, I noticed that the Application Menu had made a reappearance in the top menu. No worry I thought, I must have accidentally enabled it with the Tweaks Tool. But not so. From a quick search around it looks as though some arrogant jerk has decided that making it easy to remove is a no, no, no before spitting his dummy out.

As I couldn’t just find any up to date instructions to install a shell extension that removes said menu I provide some here.

In the Software application search for “remove app menu”. I installed the one that seems to be by rastersoft.com. (Direct link is https://extensions.gnome.org/extension/591/remove-app-menu/ ) Select the version/extension (only 3.6 and 2 available currently) and a zip file will be downloaded.

Now go to a command line, navigate to the folder containing the zip file (most likely Downloads) and type:

gnome-extensions install RemoveAppMenu@rastersoft.com.v2.shell-extension.zip

If you’re not running Wayland you can restart the shell with Alt F2 and the command r. I just restarted the machine. When you’re back up and running go in to the Tweaks Tool, Extensions tab and enable the extension. Job done.

wlan blocked

Just this week I replaced the hard drive in my laptop with a solid-state drive. As part of the process I did a clean install of Fedora 28 Workstation to the drive.

The install went very smoothly but when got into using the machine (which is now so fast!) I noticed that wi-fi was disabled. I usually use my machine on a wired connection, so it was no biggie but it’s one of those nagging things that I had to fix. I had used wi-fi in the past few weeks, so it was a new problem.

With this kind of thing you work through the list of recent changes and usually it’s one of those. So I plugged in the old drive, booted to that and found that wi-fi was still unavailable. I booted to an older kernel; still nothing.

Scouring the internet for a solution I found some useful commands. This first, iwconfig, I was familiar with. It was giving:

virbr0    no wireless extensions.
virbr0-nic no wireless extensions.
lo no wireless extensions.
wlp9s0 IEEE 802.11 ESSID:off/any
Mode:Managed Access Point: Not-Associated Tx-Power=off
Retry short limit:7 RTS thr:off Fragment thr:off
Encryption key:off
Power Management:off
enp5s0 no wireless extensions.

So the OS knew about the device. Then lspci -v gives lots of output, but of interest here is:

09:00.0 Network controller: Qualcomm Atheros AR9285 Wireless Network Adapter (PCI-Express) (rev 01)
Subsystem: Dell Wireless 1702 802.11bgn Half-size Mini PCIe Card [AR9002WB-1NGCD]
Flags: bus master, fast devsel, latency 0, IRQ 19
Memory at f7e00000 (64-bit, non-prefetchable) [size=64K]
Capabilities: [40] Power Management version 3
Capabilities: [50] MSI: Enable- Count=1/1 Maskable- 64bit-
Capabilities: [60] Express Legacy Endpoint, MSI 00
Capabilities: [100] Advanced Error Reporting
Capabilities: [140] Virtual Channel
Capabilities: [160] Device Serial Number [ Redacted ]
Capabilities: [170] Power Budgeting
Kernel driver in use: ath9k
Kernel modules: ath9k

But the command of interest was rfkill which gave:

ID TYPE      DEVICE    SOFT      HARD
0 wlan phy0 blocked blocked
1 bluetooth hci0 blocked unblocked

The device was there, but disabled in hardware. I tried the Fn-F2 key combo and that was switching airplane mode on/off, but it never enabled wi-fi.

Further Googling found a similar problem affecting Asus devices. So following that advice I reset the BIOS (set default values on this machine) and rebooted. This fixed the problem.