Skip to content

[doc] Document use of @Transactional on controller via @MessageMapping [SPR-13384] #17965

@spring-projects-issues

Description

@spring-projects-issues

Caleb Cushing opened SPR-13384 and commented

The actual cause is a little speculative (I can't imagine any reason other than the default would cause it), but I have a controller that works as expected until I implement this interace.

package com.xenoterracide.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public interface Loggable {
    default Logger log() {
        return LoggerFactory.getLogger( this.getClass() );
    }
}

Here's my controller; I realize it's a bit verbose for a test, but as soon as I removed Loggable everything started working.

package com.xenoterracide.mmp.musicdb.controller.message;

import com.xenoterracide.mmp.domain.music.Seeder;
import com.xenoterracide.mmp.domain.repository.SeederRepository;
import com.xenoterracide.mmp.domain.repository.StationRepository;
import com.xenoterracide.mmp.domain.station.Seed;
import com.xenoterracide.mmp.domain.station.Station;
import com.xenoterracide.mmp.domain.station.exception.SeedNotFoundException;
import org.springframework.context.ApplicationContext;
import org.springframework.messaging.handler.annotation.MessageExceptionHandler;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.inject.Inject;
import java.util.Optional;

@Controller
@MessageMapping( "/stations" )
public class StationMessageController {

    private final ApplicationContext context;
    private final StationRepository repository;

    @Inject
    StationMessageController( final ApplicationContext context, final StationRepository repository ) {
        this.context = context;
        this.repository = repository;
    }

    @Transactional
    @MessageMapping( "/create" )
    @SendTo( "/topic/stations/created" )
    public Station createStation( @Validated final Seed seed ) throws SeedNotFoundException {
        SeederRepository<?> seederRepository = context.getBean( seed.getType().getRepositoryClass() );
        Optional<? extends Seeder> optionalEntity = seederRepository.findOneById( seed.getSeederId() );

        Station station = optionalEntity.map( Station::new ).orElseThrow( () -> new SeedNotFoundException( seed ) );

        return repository.save( station );
    }

    @SendTo( "/topic/stations/seed-not-found" )
    @MessageExceptionHandler( SeedNotFoundException.class )
    public Seed notFound( final SeedNotFoundException e ) {
        return e.getSeed();
    }

}

By not working I mean that the controller methods are not called when broadcast to websockets: they seem to be ignored completely.


Affects: 4.1.7

Referenced from: commits 4ecb3d4

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)type: documentationA documentation task

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions