Skip to content
This repository was archived by the owner on Nov 9, 2017. It is now read-only.

Commit 4678ae6

Browse files
committed
First commit. Go nuts.
0 parents  commit 4678ae6

14 files changed

+371
-0
lines changed

Diff for: .gitignore

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.idea
2+
lib_managed
3+
target
4+
project/boot
5+
project/build/target
6+
project/plugins/lib_managed
7+
project/plugins/src_managed
8+
project/plugins/target

Diff for: LICENSE

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright (c) 2010 Coda Hale
2+
3+
Permission is hereby granted, free of charge, to any person obtaining
4+
a copy of this software and associated documentation files (the
5+
"Software"), to deal in the Software without restriction, including
6+
without limitation the rights to use, copy, modify, merge, publish,
7+
distribute, sublicense, and/or sell copies of the Software, and to
8+
permit persons to whom the Software is furnished to do so, subject to
9+
the following conditions:
10+
11+
The above copyright notice and this permission notice shall be
12+
included in all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Diff for: README.md

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
Jersey-Scala
2+
============
3+
4+
*Life's too short to use `java.util.Collection`*
5+
6+
Jersey-Scala is a set of class which add Scala interoperation to Jersey.
7+
8+
9+
Requirements
10+
------------
11+
12+
* Scala 2.8.0
13+
* Jersey 1.3
14+
15+
16+
How To Use
17+
----------
18+
19+
**First**, specify Jersey-Scala as a dependency:
20+
21+
val codaRepo = "Coda Hale's Repository" at "http://repo.codahale.com/"
22+
val jerseyScala = "com.codahale" %% "jersey-scala_1.3" % "0.1-SNAPSHOT" withSources()
23+
24+
**Second**, write your resource classes:
25+
26+
@Path("/things")
27+
@Produces("text/plain")
28+
class Things {
29+
@GET
30+
def getAThing(@QueryParam("name") names: Set[String]) = "I found: " + names.mkString(", ")
31+
}
32+
33+
34+
35+
What All This Supports
36+
----------------------
37+
38+
* `QueryParam`-annotated parameters of type `Seq[String]`, `List[String]`,
39+
`Vector[String]`, `IndexedSeq[String]`, and `Set[String]`.
40+
41+
42+
License
43+
-------
44+
45+
Copyright (c) 2010 Coda Hale
46+
47+
Published under The MIT License, see LICENSE

Diff for: notes/about.markdown

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[Jersey-Scala](https://github.com/codahale/jersey-scala) is a Scala library which
2+
allows you to use native Scala types in your Jersey application.

Diff for: project/build.properties

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#Project properties
2+
#Tue Aug 17 15:59:47 PDT 2010
3+
project.organization=com.codahale
4+
project.name=jersey-scala_1.3
5+
sbt.version=0.7.4
6+
project.version=0.1-SNAPSHOT
7+
build.scala.versions=2.8.0
8+
project.initialize=false

Diff for: project/build/JerseyScala.scala

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class JerseyScala(info: sbt.ProjectInfo) extends sbt.DefaultProject(info) with posterous.Publish with rsync.RsyncPublishing {
2+
/**
3+
* Publish the source as well as the class files.
4+
*/
5+
override def packageSrcJar= defaultJarPath("-sources.jar")
6+
val sourceArtifact = sbt.Artifact(artifactID, "src", "jar", Some("sources"), Nil, None)
7+
override def packageToPublishActions = super.packageToPublishActions ++ Seq(packageSrc)
8+
9+
/**
10+
* Publish via rsync.
11+
*/
12+
def rsyncRepo = "codahale.com:/home/codahale/repo.codahale.com"
13+
14+
/**
15+
* Dependencies
16+
*/
17+
val sunRepo = "Sun Repo" at "http://download.java.net/maven/2/"
18+
19+
val jaxrs = "javax.ws.rs" % "jsr311-api" % "1.1.1" withSources() intransitive()
20+
val jerseyCore = "com.sun.jersey" % "jersey-core" % "1.3" withSources() intransitive()
21+
val jerseyServer = "com.sun.jersey" % "jersey-server" % "1.3" withSources() intransitive()
22+
23+
val codasRepo = "Coda's Repo" at "http://repo.codahale.com"
24+
val specs = "org.scala-tools.testing" %% "specs" % "1.6.5" % "test" withSources()
25+
val simplespec = "com.codahale" %% "simplespec" % "0.2.0-SNAPSHOT" % "test" withSources()
26+
val mockito = "org.mockito" % "mockito-all" % "1.8.4" % "test" withSources()
27+
}

Diff for: project/plugins/Plugins.scala

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class Plugins(info: sbt.ProjectInfo) extends sbt.PluginDefinition(info) {
2+
val t_repo = "t_repo" at "http://tristanhunt.com:8081/content/groups/public/"
3+
val posterous = "net.databinder" % "posterous-sbt" % "0.1.4"
4+
5+
val codasRepo = "codahale.com" at "http://repo.codahale.com/"
6+
val rsync = "com.codahale" % "rsync-sbt" % "0.1.1"
7+
}

Diff for: project/plugins/project/build.properties

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#Project properties
2+
#Wed Aug 18 11:48:48 PDT 2010
3+
plugin.uptodate=true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.codahale.jersey
2+
3+
import scala.collection.JavaConversions.asIterable
4+
import scala.collection.mutable.Builder
5+
import javax.ws.rs.core.MultivaluedMap
6+
import com.sun.jersey.server.impl.model.parameter.multivalued.MultivaluedParameterExtractor
7+
8+
/**
9+
* Given a parameter name, a possibly-null default value, and a fresh collection
10+
* builder, attempts to extract all the parameter values and return a collection
11+
* instance. If defaultValue is null and no parameter exists, returns an empty
12+
* collection.
13+
*
14+
* @author coda
15+
*/
16+
class ScalaCollectionParameterExtractor[A <: Object](val parameter: String,
17+
val defaultValue: String,
18+
val builder: Builder[String, A])
19+
extends MultivaluedParameterExtractor {
20+
21+
def getName = parameter
22+
def getDefaultStringValue = defaultValue
23+
def extract(parameters: MultivaluedMap[String, String]) = {
24+
val params = parameters.get(parameter)
25+
if (params != null) {
26+
builder ++= asIterable(params)
27+
} else if (defaultValue != null) {
28+
builder += defaultValue
29+
}
30+
builder.result()
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.codahale.jersey
2+
3+
import com.sun.jersey.api.ParamException
4+
import com.sun.jersey.api.core.HttpContext
5+
import com.sun.jersey.server.impl.inject.AbstractHttpContextInjectable
6+
import com.sun.jersey.server.impl.model.parameter.multivalued.{MultivaluedParameterExtractor, ExtractorContainerException}
7+
8+
class ScalaCollectionQueryParamInjectable(val extractor: MultivaluedParameterExtractor,
9+
val decode: Boolean)
10+
extends AbstractHttpContextInjectable[Object] {
11+
12+
def getValue(c: HttpContext) = try {
13+
extractor.extract(c.getUriInfo.getQueryParameters(decode))
14+
} catch {
15+
case e: ExtractorContainerException =>
16+
throw new ParamException.QueryParamException(e.getCause,
17+
extractor.getName,
18+
extractor.getDefaultStringValue)
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.codahale.jersey
2+
3+
import scala.collection.mutable.Builder
4+
import javax.ws.rs.QueryParam
5+
import javax.ws.rs.ext.Provider
6+
import com.sun.jersey.api.model.Parameter
7+
import com.sun.jersey.core.spi.component.{ComponentScope, ComponentContext}
8+
import com.sun.jersey.spi.inject.{Injectable, InjectableProvider}
9+
10+
@Provider
11+
class ScalaCollectionsQueryParamInjectableProvider extends InjectableProvider[QueryParam, Parameter] {
12+
private val builders = Map[Class[_], Builder[String, _ <: Object]](
13+
classOf[Seq[String]] -> Seq.newBuilder[String],
14+
classOf[List[String]] -> List.newBuilder[String],
15+
classOf[Vector[String]] -> Vector.newBuilder[String],
16+
classOf[IndexedSeq[String]] -> IndexedSeq.newBuilder[String],
17+
classOf[Set[String]] -> Set.newBuilder[String]
18+
)
19+
20+
def getScope = ComponentScope.PerRequest
21+
def getInjectable(ic: ComponentContext, a: QueryParam, c: Parameter): Injectable[_] = {
22+
val parameterName = c.getSourceName()
23+
if (parameterName != null && !parameterName.isEmpty) {
24+
val builder = builders.get(c.getParameterClass)
25+
if (builder.isDefined) {
26+
new ScalaCollectionQueryParamInjectable(
27+
new ScalaCollectionParameterExtractor(parameterName, c.getDefaultValue, builder.get),
28+
!c.isEncoded
29+
)
30+
} else null
31+
} else null
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.codahale.jersey.specs
2+
3+
import com.codahale.simplespec.Spec
4+
import com.codahale.jersey.ScalaCollectionParameterExtractor
5+
import com.sun.jersey.core.util.MultivaluedMapImpl
6+
7+
object ScalaCollectionParameterExtractorSpec extends Spec {
8+
class `Extracting a query parameter` {
9+
val extractor = new ScalaCollectionParameterExtractor[Set[String]]("name", "default", Set.newBuilder[String])
10+
11+
def `should have a name` {
12+
extractor.getName must beEqualTo("name")
13+
}
14+
15+
def `should have a default value` {
16+
extractor.getDefaultStringValue must beEqualTo("default")
17+
}
18+
19+
def `should extract a set of parameter values` {
20+
val params = new MultivaluedMapImpl()
21+
params.add("name", "one")
22+
params.add("name", "two")
23+
params.add("name", "three")
24+
25+
val result = extractor.extract(params).asInstanceOf[Set[String]]
26+
result must beEqualTo(Set("one", "two", "three"))
27+
}
28+
29+
def `should use the default value if no parameter exists` {
30+
val params = new MultivaluedMapImpl()
31+
32+
val result = extractor.extract(params).asInstanceOf[Set[String]]
33+
result must beEqualTo(Set("default"))
34+
}
35+
}
36+
37+
class `Extracting a query parameter with no default value` {
38+
val extractor = new ScalaCollectionParameterExtractor[Set[String]]("name", null, Set.newBuilder[String])
39+
40+
def `should return an empty collection` {
41+
val params = new MultivaluedMapImpl()
42+
43+
val result = extractor.extract(params).asInstanceOf[Set[String]]
44+
result must beEqualTo(Set())
45+
}
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.codahale.jersey.specs
2+
3+
import com.codahale.simplespec.Spec
4+
import org.specs.mock.Mockito
5+
import com.codahale.jersey.ScalaCollectionQueryParamInjectable
6+
import com.sun.jersey.server.impl.model.parameter.multivalued.MultivaluedParameterExtractor
7+
import com.sun.jersey.api.core.{ExtendedUriInfo, HttpContext}
8+
import javax.ws.rs.core.{MultivaluedMap, UriInfo}
9+
10+
object ScalaCollectionQueryParamInjectableSpec extends Spec with Mockito {
11+
// TODO: Aug 17, 2010 <coda> -- test error handling
12+
13+
trait Context {
14+
val extractor = mock[MultivaluedParameterExtractor]
15+
val context = mock[HttpContext]
16+
val uriInfo = mock[ExtendedUriInfo]
17+
val params = mock[MultivaluedMap[String, String]]
18+
val extracted = mock[Object]
19+
20+
extractor.extract(params) returns extracted
21+
context.getUriInfo returns uriInfo
22+
}
23+
24+
class `A Scala collection query param injectable with decoding` extends Context {
25+
val injectable = new ScalaCollectionQueryParamInjectable(extractor, true)
26+
uriInfo.getQueryParameters(true) returns params
27+
28+
def `should extract the query parameters` {
29+
val e = injectable.getValue(context)
30+
31+
e must beEqualTo(extracted)
32+
}
33+
}
34+
35+
class `A Scala collection query param injectable without decoding` extends Context {
36+
val injectable = new ScalaCollectionQueryParamInjectable(extractor, false)
37+
uriInfo.getQueryParameters(false) returns params
38+
39+
def `should extract the query parameters` {
40+
val e = injectable.getValue(context)
41+
42+
e must beEqualTo(extracted)
43+
}
44+
}
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package com.codahale.jersey.specs
2+
3+
import com.codahale.simplespec.Spec
4+
import org.specs.mock.Mockito
5+
import javax.ws.rs.QueryParam
6+
import com.sun.jersey.api.model.Parameter
7+
import com.sun.jersey.core.spi.component.{ComponentContext, ComponentScope}
8+
import com.codahale.jersey.{ScalaCollectionParameterExtractor, ScalaCollectionQueryParamInjectable, ScalaCollectionsQueryParamInjectableProvider}
9+
import scala.collection.immutable.VectorBuilder
10+
import scala.collection.mutable.AddingBuilder
11+
12+
object ScalaCollectionsQueryParamInjectableProviderSpec extends Spec with Mockito {
13+
class `A Scala collections query param injectable provider` {
14+
val context = mock[ComponentContext]
15+
val provider = new ScalaCollectionsQueryParamInjectableProvider
16+
val queryParam = mock[QueryParam]
17+
18+
19+
def `should have a per-request scope` {
20+
provider.getScope must beEqualTo(ComponentScope.PerRequest)
21+
}
22+
23+
def `should decode the parameter if necessary` {
24+
val param = new Parameter(Array(), null, null, "name", null, classOf[Seq[String]], true, "default")
25+
val injectable = provider.getInjectable(context, queryParam, param).asInstanceOf[ScalaCollectionQueryParamInjectable]
26+
27+
injectable.decode must beFalse
28+
}
29+
30+
def `should return an injectable for Seq instances` {
31+
val param = new Parameter(Array(), null, null, "name", null, classOf[Seq[String]], true, "default")
32+
val injectable = provider.getInjectable(context, queryParam, param).asInstanceOf[ScalaCollectionQueryParamInjectable]
33+
34+
val extractor = injectable.extractor.asInstanceOf[ScalaCollectionParameterExtractor[Seq[String]]]
35+
extractor.parameter must beEqualTo("name")
36+
extractor.defaultValue must beEqualTo("default")
37+
extractor.builder must beEqualTo(Seq.newBuilder[String])
38+
}
39+
40+
def `should return an injectable for List instances` {
41+
val param = new Parameter(Array(), null, null, "name", null, classOf[List[String]], true, "default")
42+
val injectable = provider.getInjectable(context, queryParam, param).asInstanceOf[ScalaCollectionQueryParamInjectable]
43+
44+
val extractor = injectable.extractor.asInstanceOf[ScalaCollectionParameterExtractor[List[String]]]
45+
extractor.builder must beEqualTo(List.newBuilder[String])
46+
}
47+
48+
def `should return an injectable for Vector instances` {
49+
val param = new Parameter(Array(), null, null, "name", null, classOf[Vector[String]], true, "default")
50+
val injectable = provider.getInjectable(context, queryParam, param).asInstanceOf[ScalaCollectionQueryParamInjectable]
51+
52+
val extractor = injectable.extractor.asInstanceOf[ScalaCollectionParameterExtractor[Vector[String]]]
53+
extractor.builder must haveClass[VectorBuilder[String]]
54+
}
55+
56+
def `should return an injectable for IndexedSeq instances` {
57+
val param = new Parameter(Array(), null, null, "name", null, classOf[IndexedSeq[String]], true, "default")
58+
val injectable = provider.getInjectable(context, queryParam, param).asInstanceOf[ScalaCollectionQueryParamInjectable]
59+
60+
val extractor = injectable.extractor.asInstanceOf[ScalaCollectionParameterExtractor[IndexedSeq[String]]]
61+
extractor.builder must haveClass[VectorBuilder[String]]
62+
}
63+
64+
def `should return an injectable for Set instances` {
65+
val param = new Parameter(Array(), null, null, "name", null, classOf[Set[String]], true, "default")
66+
val injectable = provider.getInjectable(context, queryParam, param).asInstanceOf[ScalaCollectionQueryParamInjectable]
67+
68+
val extractor = injectable.extractor.asInstanceOf[ScalaCollectionParameterExtractor[Set[String]]]
69+
extractor.builder must haveClass[AddingBuilder[String, Set[String]]]
70+
}
71+
}
72+
}

0 commit comments

Comments
 (0)