3

Im using wildfly 9.0 to deploy my war file. I have java LocalDateTime, Java Money types defined in my REST GET endpoints.

When i deploy my war file, i get following error[1]. Based on this answer [2] I have written "ParamConverterProvider" implementations for both types.

It was working fine( I haven't seen same issue again till now) and now i get same issue. Any clue?

[1]

Caused by: java.lang.RuntimeException: Unable to find a constructor that takes a String param or a valueOf() or fromString() method for javax.ws.rs.QueryParam(\"totalMoneyVolumeForPeriod\") on public javax.ws.rs.core.Response com.test.rest.StockEndpoint.getItems(java.lang.Integer,java.lang.Integer,java.lang.String,java.lang.String,java.lang.Long,org.javamoney.moneta.Money,java.util.Set,java.lang.String) for basetype: org.javamoney.moneta.Money"}}}}

[2]

jaxrs could not find my custom (de)serializers for joda.money type

Sample code

package com.test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import javax.money.Monetary;
import javax.ws.rs.ext.ParamConverter;
import javax.ws.rs.ext.ParamConverterProvider;
import javax.ws.rs.ext.Provider;

import org.javamoney.moneta.Money;

@Provider
public class MoneyConverterProvider  implements ParamConverterProvider {

    private final MoneyConverter converter = new MoneyConverter();

    @Override
    public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
        if (!rawType.equals(Money.class)) return null;
        return (ParamConverter<T>) converter; 
    }

    public class MoneyConverter implements ParamConverter<Money> {

        public Money fromString(String value) {
            if (value == null ||value.isEmpty()) return null; // change this for production

            return Money.of(new BigDecimal(value), Monetary.getCurrency("AUD"));
        }

        public String toString(Money value) {
            if (value == null) return "";
            return value.toString(); // change this for production
        }

    }
}

Application claas

package com.test;

import javax.ws.rs.core.Application;

import com.test.autogen*;


import io.swagger.jaxrs.config.BeanConfig;

import java.util.HashSet;
import java.util.Set;

import javax.ws.rs.ApplicationPath;

@ApplicationPath("/rest")
public class RestApplication extends Application {
    public RestApplication() {
        BeanConfig beanConfig = new BeanConfig();
        //beanConfig.setVersion("1.0");
        beanConfig.setSchemes(new String[] { "http" });
        beanConfig.setTitle("My API");
        beanConfig.setBasePath("/rest");
        beanConfig.setResourcePackage("com.test.autogen");
        beanConfig.setScan(true);
    }

    @Override
    public Set<Class<?>> getClasses() {
        HashSet<Class<?>> set = new HashSet<Class<?>>();


        set.add(EmailEndpoint.class);
        set.add(StockEndpoint.class);

        set.add(io.swagger.jaxrs.listing.ApiListingResource.class);
        set.add(io.swagger.jaxrs.listing.SwaggerSerializers.class);

        return set;
    }
}
Community
  • 1
  • 1
Ratha
  • 9,434
  • 17
  • 85
  • 163
  • 1
    Make sure it's registered. Other than that, please show some code that we can test. – Paul Samsotha May 26 '16 at 00:02
  • @peeskillet How , Where should i register? – Ratha May 26 '16 at 00:05
  • @peeskillet i have provided my sample code..I didnt do anything other than that – Ratha May 26 '16 at 00:06
  • 1
    If you are using classpath scanning, it should be registered by the `@Provider` annotation. Other wise you need to register it in your `Application` class – Paul Samsotha May 26 '16 at 00:07
  • [here in your `Application` class in `getClasses`](http://stackoverflow.com/q/37427988/2587435) – Paul Samsotha May 26 '16 at 00:10
  • @peeskillet How to register at Application class? I have provided my Application class too. I used Provider annotation too – Ratha May 26 '16 at 00:11
  • @peeskillet thanks alot..that works fine... Sorry, this swagger libraries caused issue to me here and there..The previous one worked with the provider annotation . – Ratha May 26 '16 at 00:23

1 Answers1

3

When you are using classpath scanning, JAX-RS components annotated with @Path or @Provider will get picked up and registered. There are a couple way to use classpath scanning. The most common way is to just have an empty Application class annotated with @ApplicationPath

@ApplicationPath("/api")
public class MyApplication extends Application {}

This is enough for a JAX-RS application to be loaded, and to have the application's classpath scanned to components to register.

But, per the specification, once we override any of the Set<Object> getSingletons or Set<Class> getClasses methods of the Application class, and return a non-empty set, this automatically disables classpath scanning, as it is assumed we want to register everything ourselves.

So in previous cases, you were probably just using classpath scanning. In this case, you need to explicitly add the provider to the set of classes in your getClasses method, since you overrode the method to add other component classes.

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720