import com.sun.jersey.api.ParamException.QueryParamException import com.sun.jersey.api.core.HttpContext import com.sun.jersey.api.model.Parameter import com.sun.jersey.core.spi.component.{ComponentContext, ComponentScope} import com.sun.jersey.spi.inject.{Injectable, InjectableProvider} import com.sun.jersey.server.impl.inject.AbstractHttpContextInjectable import com.sun.jersey.server.impl.model.parameter.multivalued.MultivaluedParameterExtractor import com.sun.jersey.server.impl.model.parameter.multivalued.ExtractorContainerException import javax.ws.rs.QueryParam import javax.ws.rs.core.MultivaluedMap import javax.ws.rs.ext.Provider import org.springframework.stereotype.Component @Provider @Component class ScalaQueryParamInjectableProvider extends InjectableProvider[QueryParam, Parameter] { def getScope = ComponentScope.PerRequest def getInjectable(ic: ComponentContext, a: QueryParam, c: Parameter): Injectable[_] = { val paramName = c.getSourceName if (paramName == null || paramName.isEmpty) { null } else { ScalaQueryParamExtractor(c) match { case null => null case e => new ScalaQueryParamInjectable(e, !c.isEncoded) } } } } class ScalaQueryParamInjectable(extractor: MultivaluedParameterExtractor, decode: Boolean) extends AbstractHttpContextInjectable[Object] { def getValue(c: HttpContext): Object = try { extractor.extract(c.getUriInfo.getQueryParameters(decode)) } catch { case e: ExtractorContainerException => throw new QueryParamException(e.getCause, extractor.getName, extractor.getDefaultStringValue) } } object ScalaQueryParamExtractor { def apply(p: Parameter): MultivaluedParameterExtractor = { val klass = p.getParameterClass if (klass == classOf[Option[Int]]) new ScalaIntOptionExtractor(p) else null } } abstract class BaseScalaOptionExtractor[T](p: Parameter) extends MultivaluedParameterExtractor { val defaultValue = convert(p.getDefaultValue, None) def getName = p.getSourceName def getDefaultStringValue = p.getDefaultValue def extract(parameters: MultivaluedMap[String, String]) = convert(parameters.getFirst(p.getSourceName), defaultValue) def convert(original: String, default: Option[T]): Option[T] } class ScalaIntOptionExtractor(p: Parameter) extends BaseScalaOptionExtractor[Int](p) { def convert(original: String, default: Option[Int]): Option[Int] = original match { case null => default case x => try { Some(x.toInt) } catch { case e: NumberFormatException => throw new ExtractorContainerException("not an int", e) } } }