Showing posts with label spring. Show all posts
Showing posts with label spring. Show all posts

Friday, January 18, 2019

Spring REST testing

After too much Internet searching, I was unable to find an easy solution to repeated duplication in my Spring MockMVC tests of REST controller endpoints. For years now, the endpoints we write have typically sent or received JSON. This is what I mean:

mockMvc.perform(post("/some/endpoint")
        .contentType(APPLICATION_JSON_UTF8)
        .accept(APPLICATION_JSON_UTF8)
        .content(someRequestJson))
        .andExpect(status().isCreated())
        .andExpect(header().string(CONTENT_TYPE, APPLICATION_JSON_UTF8_VALUE))
        .andExpect(header().string(LOCATION, "/some/endpoint/name-or-id"))
        .andExpect(content().json(someResponseJson));

All the repeated "APPLICATION_JSON_UTF8"s, in every controller test!

If there is an existing Spring testing solution, I'd love to hear about it. Rather than wait, I wrote up a small extension of @WebMvcTest to default these values.

First, an annotation for Spring to use in setting up a MockMvc (javadoc elided):

@Documented
@Import(JsonMockMvcConfiguration.class)
@Retention(RUNTIME)
@Target(TYPE)
@WebMvcTest
public @interface JsonWebMvcTest {
    @AliasFor(annotation = WebMvcTest.class)
    String[] properties() default {};

    @AliasFor(annotation = WebMvcTest.class)
    Class[] value() default {};

    @AliasFor(annotation = WebMvcTest.class)
    Class[] controllers() default {};

    @AliasFor(annotation = WebMvcTest.class)
    boolean useDefaultFilters() default true;

    @AliasFor(annotation = WebMvcTest.class)
    ComponentScan.Filter[] includeFilters() default {};

    @AliasFor(annotation = WebMvcTest.class)
    ComponentScan.Filter[] excludeFilters() default {};

    @AliasFor(annotation = WebMvcTest.class)
    Class[] excludeAutoConfiguration() default {};
}

Note it is a near exact lookalike of @WebMvcTest (minus the deprecated parameter). The important bits are:

  1. Marking this annotation with @WebMvcTest, a kind of extension through composition.
  2. Adding @Import to bind custom configuration to this annotation.
  3. Tying the same-named annotation parameters to @WebMvcTest, so this annotation is a drop-in replacement of that one.

Next a configuration class, imported by the annotation, to customize MockMvc:

@Configuration
public class JsonMockMvcConfiguration {
    @Bean
    @Primary
    public MockMvc jsonMockMvc(final WebApplicationContext ctx) {
        return webAppContextSetup(ctx)
                .defaultRequest(post("/")
                        .contentType(APPLICATION_JSON_UTF8)
                        .accept(APPLICATION_JSON_UTF8_VALUE))
                .alwaysExpect(header().string(
                        CONTENT_TYPE, APPLICATION_JSON_UTF8_VALUE))
                .build();
    }
}

Some points about this class:

  • @Primary is not necessary for Spring, but helped IntelliJ — perhaps I got lucky with Spring without @Primary, and IntelliJ highlighted a real problem.
  • It took quite a while to get defaultRequest(...) working. I was unable to (re)implement the relevant interfaces, and eventually found that passing any MockHttpServletRequestBuilder sufficed. Spring "merges" (overlays) the actual request builder from the test over this default, replacing POST and "/" with whichever HTTP method and path the test uses (eg, GET "/bob"). Only the header customization is used.

Example usage:

@JsonWebMvcTest(SomeController.class)
class SomeControllerTest {
    @Autowired
    private MockMvc jsonMockMvc;

    @Test
    void shouldCheckSomething()
            throws Exception {
        jsonMockMvc.perform(post("/some/endpoint")
                .content(someRequestJson))
                .andExpect(status().isCreated())
                .andExpect(header()
                        .string(LOCATION, "/some/endpoint/new-name"))
                .andExpect(content().json(someResponseJson));
    }
}

See the Basilisk project for source code and sample usage. (Basilisk is a demonstration project for my team illustrating Spring usage and conventions.)

Sunday, September 23, 2018

Removing Joda from Spring Boot

Automated Acceptance Criteria

Removing Joda from Spring Boot

The problem

We recently migrated a medium-sized Java project to Spring Boot 2 from version 1. One of the challenges was migrating to the JDK date-time library from Joda. It turns out that Spring Boot 2 has excellent native support for JDK date-times, as does Jackson (JSON) and Hibernate (database), the default technologies offered by Spring Boot 2 for these features.

The migration itself went smoothly, which is unsurprising given the fantastic work of Stephen Colebourne in designing JDK date-time support based on his authorship of Joda.

So we looked at disabling Joda completely in our Gradle build. The most concise approach we found was:

configurations {
    compile.exclude group: 'joda-time'
}

This removed Joda completely from configurations (classpaths) related to Java. However, this had unintended side effects:

  • During tests, we needed Joda in the runtime classpath for a 3rd-party library, OpenSAML
  • During boot run (running the app), we needed Joda in the classpath for another 3rd-party library, SpringFox

We easily found a workaround for SpringFox, but not for OpenSAML.

(If you're curious, yes, we do intent to migrate from OpenSAML 2 (desupported in 2016) to OpenSAML 3; however, we would like spring-security-saml2-core support first.)

A solution in progress

The exclusion in the compile configuration does exactly what we need: Joda disappears! But what to do about SpringFox and OpenSAML?

For the Spring Boot runtime classpath, there is another concise solution, though finding it was rather troublesome, and it is not well-documented by Pivotal or in Stack Overflow.

First, we setup another classpath of our own making named bootRuntime:

configurations {
    // Other parts of "configurations", including the Joda exclusion from above

    bootRuntime // Synthetic configuration for deps needed *only* to launch app
}

Then we added Joda to that synthetic classpath relying on Spring Boot plugin's definition for the version of Joda to use:

dependencies {
    // Other parts of "dependencies"

    bootRuntime 'joda-time:joda-time'
}

Lastly, we taught Spring Boot to include this synthetic classpath when launching our app (this was the trickiest part):

bootJar {
    bootInf {
        from configurations.bootRuntime
        into 'lib'
    }
}

bootRun {
    classpath += configurations.bootRuntime
}

This adds Joda to the runtime classpath for both the single "fat jar" built by Spring (bootJar), and when launching the app on the command line with gradle (bootRun).

Unless you are a heavy Gradle user, from ... into ... syntax may be unfamiliar: this copies the jars in the synthetic configuration into the fat jar at the location Boot expects to find them. The "'lib'" is literally a directory location within the jar. Useful magic, but a bit obtuse. The outcome:

$ jar tf build/libs/the-project.jar | grep joda-time
BOOT-INF/lib/joda-time-2.9.9.jar

As a matter of fact, Joda is the very last file in the boot jar, a suggestion that it was added by our bootInf section after the Boot plugin built the jar.

(Our workaround is intentionally small. If we're unable to make it work, we'll switch to brute-force library exclusions in our dependencies lists. The goal is to prevent accidental import from Joda, for example, of LocalDate.)

Remaining work

For running the boot app, this solution is great: it is small, readable, easy to maintain, and it works. However, for tests which exercise our user authentication with OpenSAML, it fails. Joda is not in the test classpath, and we cannot use or mock OpenSAML methods which use Joda types.

Barring another magical solution like bootRuntime, we'll fall back on manually excluding Joda from each dependency, and adding it back in to the test classpath. A pity given how pithy the solution is with exclusion from the compile configuration.

Sunday, July 29, 2018

Kotlin JPA patterns

Kotlin JPA pattern

The problem

Kotlin does many wonderful things for you. For example, the data classes create helpful constructors, and automatically implement equals and hashCode in a reasonable way.

Similarly, JPA works magic—expecially in the context of Spring Data.

So how do I test that my Kotlin entity is correctly annotated for JPA? The simplest thing would be a "round trip" test: create an entity, save it to a database, read it back, and confirm the object has the same values. Let's start with a simple entity, and the simplest possible test:

@Entity
data class Greeting(
        val content: String,
        @Id @GeneratedValue
        val: Int id = 0)
@DataJpaTest
@ExtendWith(SpringExtension::class)
internal class GreetingRepositoryIT(
        @Autowired val repository: GreetingRepository,
        @Autowired val entityManager: EntityManager) {
    @DisplayName("WHEN saving a greeting properly annotated")
    @Nested
    inner class Roundtrip {
        @Test
        fun `THEN is can be read back`() {
            val greeting = Greeting("Hello, world!")

            repository.saveAndFlush(greeting.copy())
            entityManager.clear()

            assertThat(repository.findOne(Example.of(greeting)).get())
                    .isEqualTo(greeting)
        }
    }
}

Some things to note:

  1. To ensure we truly read from the database, and not the entity manager's in-memory cache, flush the object and clear the cache.
  2. As saving also updates the entity's id field, save a copy, so our original is untouched.
  3. Be careful to use saveAndFlush on the Spring repository, rather than entityManager.flush(), which requires a transaction, and would add unneeded complexity to the test.

But this test fails! Why?

The unsaved entity (remember, we made a copy to keep the original pristine) does not have a value for id, and the entity read back does. Hence, the automatically generated equals method says the two objects differ because of id (null in the original vs some value from the database).

Further, the Spring Data QBE (QBE) search for our entity includes id in the search criteria. Even changing equals would not address this.

What to do?

The solution

It turns out we need to address two issues:

  1. The generated equals takes id into account, but we are only interested in the data values, not the database administrivia.
  2. The test look up in the database includes the SQL id column. Although we could try repository.getOne(saved.id), I'd prefer to keep using QBE, if the code is reasonable.

To address equals, we can rely on an interesting fact about Kotlin data classes: only default constructor parameters are used, not properties in the class body, when generating equals and hashCode. Hence, I write the entity like this, and equals does not include id, while JPA is stil happy as it relies on getter reflection:

@Entity
data class Greeting(
        val content: String) {
    @Id
    @GeneratedValue
    val id = 0
}

To address the test, we can ask QBE to ignore id when fetching our saved entity back from the database:

@DataJpaTest
@ExtendWith(SpringExtension::class)
internal class GreetingRepositoryIT(
        @Autowired val repository: GreetingRepository,
        @Autowired val entityManager: EntityManager) {
    @DisplayName("WHEN saving a greeting properly annotated")
    @Nested
    inner class Roundtrip {
        @Test
        fun `THEN is can be read back`() {
            val greeting = Greeting("Hello, world!")

            repository.saveAndFlush(greeting.copy())
            entityManager.clear()

            val matcher = ExampleMatcher.matching()
                    .withIgnoreNullValues()
                    .withIgnorePaths("id")
            val example = Example.of(greeting, matcher);

            assertThat(repository.findOne(example).get()).isEqualTo(greeting)
        }
    }
}

In a larger database, I'd look into providing an entity.asExample() to avoid duplicating ExampleMatcher in each test.

Java approach

The closest to Kotlin's data classes for JPA entities is Lombok's @Data annotation, together with @EqualsAndHashCode(exclude = "id") and @Builder(toBuilder = true), however the expressiveness is lower, and clutter higher.

The test would be largely the same modulo language, replacing greeting.copy() with greeting.toBuilder().build(). Alternatively, rather than a QBE matcher, one could write greeting.toBuilder().id(null).build().

This last fact leads to an alternative with Kotlin: include id in the data class' default constructor, and in the test compare the QBE result as findOne(example).get().copy(id = null) without a matcher.

Conclusion

What Kotlin JPA patterns have you discovered?

Tuesday, January 09, 2018

Sproingk lives!

Sproingk lives!

After months of instability, I again have a fully working pipeline and a live web page for Sproingk, my demo project combining the latest public betas in:

If you're interested in any combination of these, please take a gander.

About some of the items

Kotlin (It's not just for Android!) is really where JVM programming is headed. And it's fun.

Springfox gives you a lovely UI for your REST API. (In the demo, try the "greeting controller".)

Boxfuse make minimal shrink-wrapped Linux images of your software, and handles blue/green AWS deployments.

Sunday, February 21, 2016

Followup: Feature Toogles for Spring

The original technique in Spring Techniques: Feature toggles for controller request handler methods works well in the small but failed for our large project. We have too many snowflakes, customized replumbing of Spring and Boot, and destructive interference forced another path. So we went with AOP, the magical fallback in such situations, a pity.

But help is on the way!

The Togglz project is close to an official solution for the 2.3.0 release (no timeline announced). I am pleased with the solution taken and contributed a small bit. Here's the documentation commit. Please try 2.3.0-RC1 when it goes to Maven Central.

Sunday, January 10, 2016

Spring Techniques: Feature toggles for controller request handler methods

Maria Gomez, a favorite colleague, asked a wonderful question, "How can I have feature toggles on Spring MVC controller request handler methods?" Existing Java feature toggle libraries focus on toggling individual beans, or using if/else logic inside methods, and don't work at the method level.

Given a trivial example toggle:

@Documented
@Retention(RUNTIME)
@Target(METHOD)
public @interface Enabled {
    boolean value();
}

I'd like my controller to work like this:

@RestController
@RequestMapping(PATH)
public class HelloWorldController {
    public static final String PATH = "/hello-world";

    private static final String texanTemplate = "Howdy, %s!";
    private static final String russianTemplate = "Привет, %s!";
    private final AtomicLong counter = new AtomicLong();

    @Enabled(true)
    @RequestMapping(value = "/{name}", method = GET)
    public Greeting sayHowdy(@PathVariable("name") final String name) {
        return new Greeting(counter.incrementAndGet(),
                format(texanTemplate, name));
    }

    @Enabled(false)
    @RequestMapping(value = "/{name}", method = GET)
    public Greeting sayPrivet(@PathVariable("name") final String name) {
        return new Greeting(counter.incrementAndGet(),
                format(russianTemplate, name));
    }
}

(Greeting is a simple struct turned into JSON by Spring.)

To make the example a little more sophisticated, I'd like to use a "3rd-party library" to decide on which features to activate (think "Togglz" or "FF4J", say):

@Component
public class EnabledChecker {
    public boolean isMapped(final Enabled enabled) {
        return null == enabled || enabled.value();
    }
}

Originally I investigated Spring's RequestCondition classes, thinking I could do the same as @RequestMapping(... match conditions ...). However, this is tricky! Spring uses these conditions to decide which method to invoke for each HTTP request, not when deciding which methods should be treated as the handler for a given HTTP path. Taking this route, Spring complains at wiring time of duplicate handlers for the same request path.

The right way is to control the initial wiring of request handler methods, not decide later. First extend RequestMappingHandlerMapping (what a mouthful!):

public class EnabledRequestMappingHandlerMapping
        extends RequestMappingHandlerMapping {
    @Autowired
    private EnabledChecker checker;

    @Override
    protected RequestMappingInfo getMappingForMethod(final Method method,
            final Class<?> handlerType) {
        final Enabled enabled = findAnnotation(method, Enabled.class);
        final boolean mapped = checker.isMapped(enabled);
        return mapped ? super.getMappingForMethod(method, handlerType) : null;
    }
}

Note this is not directly a bean (no @Component). We need one more bit, to override the factory method that creates these handler mappings:

@Configuration
public class EnabledWebMvcConfigurationSupport
        extends WebMvcConfigurationSupport {
    @Override
    protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
        return new EnabledRequestMappingHandlerMapping();
    }
}

And Bob's your uncle. EnabledWebMvcConfigurationSupport ensures the returned ReqeustMappingHandlerMapping is injected, and so the "3rd-party library" is available to consult.

Full code in Github.

Wednesday, December 23, 2015

Looking for problematic logging with JUnit

Stefan Birkner's System Rules is one of my favorite JUnit extension libraries. I commonly use it to verify System.out and System.err, for example validating audit trail logging.

Growing tired of the same boilerplate, I rolled some simple rules into an aggregated JUnit @Rule, called NiceLoggingRule. It enforces:

  • No logging to System.err
  • No WARN or ERROR logging to System.out

A more sophisticated version would let the user decide on more than "log level" as to what is an acceptable log line, but it gives a good demonstration of writing complex JUnit rules:

public final class NiceLoggingRule
        implements TestRule {
    private static final Pattern NEWLINE = compile("\n");

    private final SystemOutRule sout = new SystemOutRule().
            enableLog().
            muteForSuccessfulTests();
    private final SystemErrRule serr = new SystemErrRule().
            enableLog();

    private final Pattern logLinePattern;
    private final Predicate<String> problematic;
    private final RuleChain delegate;

    public NiceLoggingRule(final String logLinePattern,
            final Predicate<String> problematic) {
        this.logLinePattern = compile(logLinePattern);
        this.problematic = problematic;
        delegate = outerRule(NiceLoggingStatement::new).
                around(sout).
                around(serr);
    }

    @Override
    public Statement apply(final Statement base,
            final Description description) {
        return delegate.apply(base, description);
    }

    private final class NiceLoggingStatement
            extends Statement {
        private final Statement base;
        private final Description description;

        private NiceLoggingStatement(final Statement base,
                final Description description) {
            this.base = base;
            this.description = description;
        }

        @Override
        public void evaluate()
                throws Throwable {
            base.evaluate();
            checkSystemErr(description);
            checkSystemOut(description);
        }

        private void checkSystemErr(final Description description) {
            final String cleanSerr = serr.getLogWithNormalizedLineSeparator();
            final List<String> errors = NEWLINE.splitAsStream(cleanSerr).
                    collect(toList());
            if (!errors.isEmpty())
                fail("Output to System.err from " + description + ":\n"
                        + cleanSerr);
        }

        private void checkSystemOut(final Description description) {
            final String cleanSout = sout.getLogWithNormalizedLineSeparator();
            final List<LogLine> problems = NEWLINE.splitAsStream(cleanSout).
                    map(LogLine::new).
                    filter(LogLine::problematic).
                    collect(toList());
            if (!problems.isEmpty())
                fail(problems.stream().
                        map(Object::toString).
                        collect(joining("",
                                "Problems to System.out from " + description
                                        + ":\n", "")));
        }
    }

    private final class LogLine {
        @Nonnull
        private final String line;
        @Nonnull
        private final String level;

        private LogLine(@Nonnull final String line) {
            final Matcher match = logLinePattern.matcher(line);
            if (!match.find()) // Not match! Ignore trailing CR?NL
                fail(format(
                        "Log line does not match expected pattern (%s): %s",
                        logLinePattern.pattern(), line));
            this.line = line;
            level = match.group("level");
        }

        public boolean problematic() {
            return problematic.test(level);
        }

        @Override
        public String toString() {
            return line;
        }
    }
}

For example, using it with Spring Boot's default log pattern one might write a factory helper:

public final class SpringDefaultNiceLoggingRule {
    private static final String logLevels = Stream.of(LogLevel.values()).
            filter(level -> OFF != level).
            map(Enum::name).
            collect(joining("|"));

    public static NiceLoggingRule springDefaultNiceLoggingRule() {
        return new NiceLoggingRule(
                "^(?<timestamp>\\d{4,4}-\\d{2,2}-\\d{2,2} \\d{2,2}:\\d{2,2}:\\d{2,2}\\.\\d{3,3}) +(?<level>"
                        + logLevels + ") +",
                SpringDefaultNiceLoggingRule::problematic);
    }

    private static boolean problematic(final String level) {
        return 0 > INFO.compareTo(LogLevel.valueOf(level));
    }
}

Then a simple Spring Boot unit test becomes:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MockServletContext.class)
public final class RootControllerTest {
    @Rule
    public final NiceLoggingRule niceLogging = springDefaultNiceLoggingRule();

    private MockMvc mvc;

    @Before
    public void setUp()
            throws Exception {
        mvc = standaloneSetup(new RootController()).build();
    }

    @Test
    public void shouldGetRoot()
            throws Exception {
        mvc.perform(get("/").
                accept(APPLICATION_JSON_UTF8)).
                andExpect(status().isOk()).
                andExpect(jsonPath("$.message", equalTo("Hello, world!")));
    }
}

Saturday, December 19, 2015

Spring REST showcase

I've noodled for some time now at mini-projects showcasing Spring REST with as many bells and whistles as I could pack in before it broke. I've never reached a satisfactory conclusion, which is more a testament to my mercurial temperament than to Spring. My ideal project would include:

  • No XML, if avoidable (Lombok, I'm looking at you)
  • No properties files (thank you, Spring YAML support)
  • Annotations and code generation (thank you, Spring Boot and Lombok)
  • Good documentation (Swagger and RAML, why do you need to be so tricky?)
  • Complete REST adherence (HATEOAS, you are still an ugly child, sorry to say that)
  • Modern Java
  • No external container (Spring Boot to the rescue!)
  • Many example integration points (and this is why I stay with you Spring)
  • Maven build (sorry Gradle, I gave up makefiles so I would never again debug my build)
  • Production support (Spring actuator: genius; see OSI)
  • Cloud support
  • Full CD pipeline (Boxfuse, you may save me yet; Github and Travis, you're still the best)

Essentially I want to implement a showcase REST microservice adhering to Larry Wall's three great virtues of a programmer: Laziness, Impatience and Hubris.

Well, there's always yet another Github repo.

Updates I'll keep updating this post as I find new things to desire in a showcase project.

Thursday, October 15, 2015

Spring advice

Today I had an exchange with an erstwhile colleague, one of those talented few equally comfortable in C++ and Java, great with demanding clients and fellow developers. He asked me for thoughts on Spring dependency injection. Branching out a bit, I replied:

Matter of taste/opinion.

Some things I prefer:

  • Avoid setter injection if at all possible. I want my beans to be finished after DI, not changeable at runtime on accident (very nasty bug to track down) Constructor injection most preferred, followed by field
  • Use standard annotations rather than Spring ones (@Inject), though @Value is needed for injected configuration if you're not using a dedicated configuration object
  • Spring Java configuration beats XML almost all the time
  • If the program doesn't need Spring DI, I prefer using Guice or Dagger. They're simpler, everything is at compile time, and error messages are better. The Spring non-DI libraries play fine with others (e.g., spring-jdbc)
  • Avoid mixing business objects with wiring unless it makes sense. For example, JdbcTemplate should be new'ed as needed, injecting only the DataSource. Injecting the template is an anti-pattern
  • Do use Spring Boot or Dropwizard, et al, if it makes sense. Big time savers, lots of good integration prepackaged
  • For webby programs (apps, services) remember to test unit, controller and integration separately. Spring boot intro page has excellent code examples

Things get more interesting with multiple configurations and with cloud. For example:

  • Do you make separate builds for each env, or one build with multiple configurations? Latter is traditional in EE world, former much better for cloud (devops, immutable, unikernel, etc)
  • Do you pull in configuration externally, e.g., Spring Cloud Config, Netflix Archaius or Apache Zookeeper. I like this approach, but more complex and overkill for simple programs. Nearly mandatory for microservices, and strong choice when in cloud

Did I answer fairly?

Wednesday, March 05, 2014

World's smallest DAO

The world's smallest Java DAO (with heavy lifting provided by Spring Framework):

public class SimpleDAO {
    private final DataSourceTransactionManager transactionManager;

    public SimpleDAO(DataSourceTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    public <T> T dao(Dao<T> dao) {
        return dao.using(transactionManager);
    }

    public interface Dao<T> {
        default T using(DataSourceTransactionManager transactionManager) {
            return new TransactionTemplate(transactionManager).execute(
                    status -> on(new JdbcTemplate(transactionManager.getDataSource()), status));
        }

        T on(JdbcTemplate jdbcTemplate, TransactionStatus status);
    }
}

Usage:

class InviteesDAO {
    private final SimpleDAO transact;

    InviteesDAO(DatabaseTransactionManager transactionManager) {
        transact = new SimpleDAO(tranactionManager);
    }

    List<String> getInvitees() {
        return transact.dao((jdbcTemplate, status) -> jdbcTemplate.queryForList(
            "SELECT username FROM invitees", String.class));
    }

    void invite(String username) {
        transact.dao((jdbcTemplate, status) -> jdbcTemplate.update(
            "INSERT INTO invitees (username) VALUES (?)", username));
    }
}

UPDATE: Demonstrate with composition rather than inheritance.

Friday, February 07, 2014

ServiceBinder

I've released ServiceBinder 0.2 to Maven Central (details below; soon to be 0.3 with more documentation). I wrote this to fix a common problem for my projects.

I like using the JDK ServiceLoader for discovery: it is simple to use and understand and always available. And Kawaguchi's META-INF/services generator makes use as simple as an annotation.

However, ServiceLoader is missing one key feature for me. It requires a default constructor for implementations, and I am a fan of constructor injection.

ServiceBinder fills this gap. It discovers service classes as ServiceLoader does, and injects them with Guice or Spring. See the GitHub site for examples and source. A taste:

Guice

public final class SampleModule
        extends AbstractModule {
    @Override
    protected void configure() {
        ServiceBinder.with(binder()).bind(Bob.class);
    }
}

Spring Framework

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AppConfig.class);
ServiceBinder.with(context).bind(Bob.class);
context.refresh();

Friday, January 14, 2011

Teach Spring to use per-listener JMS destination queue names, not hard-coded ones

This took some experimenting.

My problem: I am using Spring Framework 3.0 JMS support to wire up a JMS listener container to listener beans. The XML syntax looks like:

<jms:listener-container>
    <jms:listener
            destination="hard-coded-queue-name"
            ref="listener"/>
</jms:listener-container>

This XML is distributed with each program instance. Not a single single server or client instance but a server cluster or client farm: each one of these needs a unique destination so JMS routes correctly.

My first try fixed the uniqueness problem but was less than fully usable:

<jms:listener-container>
    <jms:listener
            destination="#{T(java.util.UUID).randomUUID().toString()}"
            ref="listener"/>
</jms:listener-container>

This suffers excess cleverness. Each listener gets a random UUID for its destination. But, how does the listener refer to this queue name when filling in a JMS reply-to field, or logging or other purposes?

The real answer is to ask the listener for a destination, no produce one externally:

<jms:listener-container>
    <jms:listener
            destination="#{listener.inbox}"
            ref="listener"/>
</jms:listener-container>

And in the listener:

private final String inbox = UUID.randomUUID().toString();

public String getInbox() {
    return inbox;
}

Tuesday, December 07, 2010

Jumping off into Spring with Maven

I keep wasting time rediscovering the right Maven dependencies for Spring Framework. I could have just read Keith Donald's blog post.

Monday, January 26, 2009

Stumbled on: GuiceyFruit

While trying out mvnbrowser I stumbled on GuiceyFruit, a value-add to Guice by James Strachan and Willem Jiang (no blog?).

GuiceyFruit hits the right notes for me: integration of Guice into lots of nice places, especially that EJB3/J2EE business some of my coworkers talk about. Spring-to-Guice converter is cute.

And a bonus: a nice Maven repo tracking Guice 2.x development.