Skip to content
This repository was archived by the owner on Feb 8, 2023. It is now read-only.

Commit a97558c

Browse files
Merge pull request #2 from js-cookie/docs
Add documentation
2 parents eb39372 + 32ea97c commit a97558c

File tree

6 files changed

+331
-3
lines changed

6 files changed

+331
-3
lines changed

CONTRIBUTING.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
## Issues
2+
3+
- Report issues or feature requests on [GitHub Issues](https://github.com/js-cookie/java-cookie/issues).
4+
- If reporting a bug, please add a [simplified example](http://sscce.org/).
5+
6+
## Pull requests
7+
- Create a new topic branch for every separate change you make.
8+
- Create a test case if you are fixing a bug or implementing an important feature.
9+
- Make sure the build runs successfully [(see below)](#development).
10+
11+
## Development
12+
13+
### Tools
14+
We use the following tools for development:
15+
16+
- [Maven](https://maven.apache.org/) for Java Build.
17+
- [NodeJS](http://nodejs.org/download/) required to run grunt.
18+
- [Grunt](http://gruntjs.com/getting-started) for JavaScript task management.
19+
20+
### Getting started
21+
22+
Install [NodeJS](http://nodejs.org/).
23+
Install [Maven](https://maven.apache.org/download.cgi) and add `mvn` as a global alias to run the `/bin/mvn` command inside Maven folder.
24+
25+
Browse to the project root directory and run the build:
26+
27+
$ mvn install
28+
29+
After the build completes, you should see the following message in the console:
30+
31+
----------------------------------------------------------------------------
32+
BUILD SUCCESS
33+
----------------------------------------------------------------------------
34+
35+
### Unit tests
36+
To run the unit tests, execute the following command:
37+
38+
$ mvn test
39+
40+
### Integration tests
41+
42+
If you want to debug the integration tests in the browser, switch `Debug.FALSE` to `Debug.TRUE` in `CookiesEncodingIT.java` and run the build:
43+
44+
$ mvn install
45+
46+
[Arquillian](http://arquillian.org/) will start the server, [Selenium](http://www.seleniumhq.org/) will run the tests in Firefox, but the build will hang to allow debugging in the browser.

README.md

Lines changed: 266 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,267 @@
11
# Java Cookie
2-
A simple Java Servlet API for handling cookies
2+
3+
A simple Java API for handling cookies
4+
5+
* [Unobstrusive](#json-data-binding) JSON Data Binding support
6+
* [RFC 6265](http://www.rfc-editor.org/rfc/rfc6265.txt) compliant
7+
* Enable [custom decoding](#converter)
8+
9+
## Basic Usage
10+
11+
Create a cookie, valid across the entire site
12+
13+
```java
14+
Cookies cookies = Cookies.initFromServlet( request, response );
15+
cookies.set( "name", "value" );
16+
```
17+
18+
Create a cookie that expires 7 days from now, valid across the entire site:
19+
20+
```java
21+
Cookies cookies = Cookies.initFromServlet( request, response );
22+
cookies.set( "name", "value", Attributes.empty()
23+
.expires( Expiration.days( 7 ) )
24+
);
25+
```
26+
27+
Create an expiring cookie, valid to the path of the current page:
28+
29+
```java
30+
Cookies cookies = Cookies.initFromServlet( request, response );
31+
cookies.set( "name", "value", Attributes.empty()
32+
.expires( Expiration.days( 7 ) )
33+
.path( "" )
34+
);
35+
```
36+
37+
Read cookie:
38+
39+
```java
40+
Cookies cookies = Cookies.initFromServlet( request, response );
41+
cookies.get( "name" ); // => "value"
42+
cookies.get( "nothing" ); // => null
43+
```
44+
45+
Read all available cookies:
46+
47+
```java
48+
Cookies cookies = Cookies.initFromServlet( request, response );
49+
Map<String, String> all = cookies.get(); // => {name=value}
50+
```
51+
52+
Delete cookie:
53+
54+
```java
55+
Cookies cookies = Cookies.initFromServlet( request, response );
56+
cookies.remove( "name" );
57+
```
58+
59+
Delete a cookie valid to the path of the current page:
60+
61+
```java
62+
Cookies cookies = Cookies.initFromServlet( request, response );
63+
cookies.set( "name", "value", Attributes.empty()
64+
.path( "" )
65+
);
66+
cookies.remove( "name" ); // fail!
67+
cookies.remove( "name", Attributes.empty().path( "path" ) ); // removed!
68+
```
69+
70+
*IMPORTANT! when deleting a cookie, you must pass the exact same path, domain and secure attributes that were used to set the cookie, unless you're relying on the [default attributes](#cookie-attributes).*
71+
72+
## JSON Data Binding
73+
74+
java-cookie provides unobstrusive JSON storage for cookies with data binding.
75+
76+
When creating a cookie, you can pass a few supported types instead of String in the value. If you do so, java-cookie will store the stringified JSON representation of the value using [jackson databind](https://github.com/FasterXML/jackson-databind/#use-it).
77+
78+
Consider the following class that implements the `CookieValue` interface:
79+
80+
```java
81+
public class Person implements CookieValue {
82+
private int age;
83+
public Person( int age ) {
84+
this.age = age;
85+
}
86+
public int getAge() {
87+
return age;
88+
}
89+
}
90+
```
91+
92+
And the following usage:
93+
94+
```java
95+
Cookies cookies = Cookies.initFromServlet( request, response );
96+
cookies.set( "name", new Person( 25 ) );
97+
```
98+
99+
When reading a cookie with the default `get()` api, you receive the string representation stored in the cookie:
100+
101+
```java
102+
Cookies cookies = Cookies.initFromServlet( request, response );
103+
String value = cookies.get( "name" ); // => "{\"age\":25}"
104+
```
105+
106+
If you pass the type reference, it will parse the JSON into a new instance:
107+
108+
```java
109+
Cookies cookies = Cookies.initFromServlet( request, response );
110+
Person adult = cookies.get( "name", Person.class );
111+
if ( adult != null ) {
112+
adult.getAge(); // => 25
113+
}
114+
```
115+
116+
## Encoding
117+
118+
This project is [RFC 6265](http://tools.ietf.org/html/rfc6265#section-4.1.1) compliant. All special characters that are not allowed in the cookie-name or cookie-value are encoded with each one's UTF-8 Hex equivalent using [percent-encoding](http://en.wikipedia.org/wiki/Percent-encoding).
119+
The only character in cookie-name or cookie-value that is allowed and still encoded is the percent `%` character, it is escaped in order to interpret percent input as literal.
120+
To override the default cookie decoding you need to use a [converter](#converter).
121+
122+
## Cookie Attributes
123+
124+
the default cookie attributes can be set globally by setting properties of the `.defaults()` instance or individually for each call to `.set(...)` by passing an `Attributes` instance in the last argument. Per-call attributes override the default attributes.
125+
126+
```java
127+
Cookies cookies = Cookies.initFromServlet( request, response );
128+
cookies.defaults()
129+
.secure( true )
130+
.httpOnly( true );
131+
cookies.set( "name", "value", Attributes.empty()
132+
.httpOnly( false ) // override defaults
133+
);
134+
```
135+
136+
### expires
137+
138+
Define when the cookie will be removed. Value can be an `Expiration.days()` which will be interpreted as days from time of creation, a `java.util.Date` or an `org.joda.time.DateTime` instance. If omitted, the cookie becomes a session cookie.
139+
140+
**Default:** Cookie is removed when the user closes the browser.
141+
142+
**Examples:**
143+
144+
```java
145+
DateTime date_2015_06_07_23h38m46s = new DateTime( 2015, 6, 7, 23, 38, 46 );
146+
Cookies cookies = Cookies.initFromServlet( request, response );
147+
cookies.set( "name", "value", Attributes.empty()
148+
.expires( Expiration.date( date_2015_06_07_23h38m46s ) )
149+
);
150+
cookies.get( "name" ); // => "value"
151+
cookies.remove( "name" );
152+
```
153+
154+
### path
155+
156+
Define the path where the cookie is available.
157+
158+
**Default:** `/`
159+
160+
**Examples:**
161+
162+
```java
163+
Cookies cookies = Cookies.initFromServlet( request, response );
164+
Attributes validToTheCurrentPage = Attributes.empty().path( "" );
165+
cookies.set( "name", "value", validToTheCurrentPath );
166+
cookies.get( "name" ); // => "value"
167+
cookies.remove( "name", validToTheCurrentPath );
168+
```
169+
170+
### domain
171+
172+
Define the domain where the cookie is available
173+
174+
**Default:** Domain of the page where the cookie was created
175+
176+
**Examples:**
177+
178+
```java
179+
Cookies cookies = Cookies.initFromServlet( request, response );
180+
cookies.set( "name", "value", Attributes.empty().domain( "sub.domain.com" ) );
181+
cookies.get( "name" ); // => null (need to read at "sub.domain.com")
182+
```
183+
184+
### secure
185+
186+
A `Boolean` indicating if the cookie transmission requires a secure protocol (https)
187+
188+
**Default:** No secure protocol requirement
189+
190+
**Examples:**
191+
192+
```java
193+
Cookies cookies = Cookies.initFromServlet( request, response );
194+
Attributes secureCookie = Attributes.empty().secure( true );
195+
cookies.set( "name", "value", secureCookie );
196+
cookies.get( "name" ); // => "value"
197+
cookies.remove( "name", secureCookie );
198+
```
199+
200+
### httpOnly
201+
202+
A `Boolean` indicating if the cookie should be restricted to be manipulated only in the server.
203+
204+
**Default:** The cookie can be manipulated in the server and in the client
205+
206+
**Examples:**
207+
208+
```java
209+
Cookies cookies = Cookies.initFromServlet( request, response );
210+
Attributes httpOnlyCookie = Attributes.empty().httpOnly( true );
211+
cookies.set( "name", "value", httpOnlyCookie );
212+
cookies.get( "name" ); // => "value"
213+
cookies.remove( "name", httpOnlyCookie );
214+
```
215+
216+
## Converter
217+
218+
Create a new instance of the api that overrides the default decoding implementation.
219+
All methods that rely in a proper decoding to work, such as `remove()` and `get()`, will run the converter first for each cookie.
220+
The returning String will be used as the cookie value.
221+
222+
Example from reading one of the cookies that can only be decoded using the Javascript `escape` function:
223+
224+
``` java
225+
// document.cookie = 'escaped=%u5317';
226+
// document.cookie = 'default=%E5%8C%97';
227+
228+
Cookies cookies = Cookies.initFromServlet( request, response );
229+
Cookies escapedCookies = cookies.withConverter(new Cookies.Converter() {
230+
@Override
231+
public String convert( String value, String name ) throws ConverterException {
232+
ScriptEngine javascript = new ScriptEngineManager().getEngineByName( "JavaScript" );
233+
if ( name.equals( "escaped" ) ) {
234+
try {
235+
return javascript.eval( "unescape('" + value + "')" ).toString();
236+
} catch ( ScriptException e ) {
237+
throw new ConverterException( e );
238+
}
239+
}
240+
return null;
241+
}
242+
});
243+
244+
escapedCookies.get( "escaped" ); // => 北
245+
escapedCookies.get( "default" ); // => 北
246+
escapedCookies.get(); // => {escaped=北, default=北}
247+
```
248+
249+
Instead of passing a converter inline, you can also create a custom strategy by implementing the `ConverterStrategy` interface:
250+
251+
```java
252+
class CustomConverter implements ConverterStrategy {
253+
@Override
254+
public String convert( String value, String name ) throws ConverterException {
255+
return value;
256+
}
257+
}
258+
```
259+
260+
```java
261+
Cookies cookies = Cookies.initFromServlet( request, response );
262+
Cookies cookiesWithCustomConverter = cookies.withConverter( new CustomConverter() );
263+
```
264+
265+
## Contributing
266+
267+
Check out the [Contributing Guidelines](CONTRIBUTING.md).

src/main/java/org/jscookie/ConverterStrategy.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package org.jscookie;
22

3-
interface ConverterStrategy {
3+
public interface ConverterStrategy {
44
/**
55
* Apply the decoding strategy of a cookie. The return will be used as the cookie value
66
*

src/main/java/org/jscookie/CookieParseException.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package org.jscookie;
22

3-
public class CookieParseException extends Exception {
3+
public final class CookieParseException extends Exception {
44
private static final long serialVersionUID = 1;
5+
@SuppressWarnings( "unused" )
6+
private CookieParseException() {}
57
CookieParseException( Throwable cause ) {
68
super( cause );
79
}

src/main/java/org/jscookie/CookieSerializationException.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
public class CookieSerializationException extends Exception {
44
private static final long serialVersionUID = 1;
5+
@SuppressWarnings( "unused" )
6+
private CookieSerializationException() {}
57
CookieSerializationException( Throwable cause ) {
68
super( cause );
79
}

src/test/java/org/jscookie/test/unit/CookiesConverterTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import javax.script.ScriptException;
66

77
import org.jscookie.ConverterException;
8+
import org.jscookie.ConverterStrategy;
89
import org.jscookie.Cookies;
910
import org.jscookie.test.unit.utils.BaseTest;
1011
import org.junit.Assert;
@@ -51,4 +52,16 @@ public String convert( String value, String name ) throws ConverterException {
5152
expected = "京";
5253
Assert.assertEquals( expected, actual );
5354
}
55+
56+
@Test
57+
public void should_be_able_to_create_a_custom_strategy() {
58+
this.cookies.withConverter( new CustomConverter() );
59+
}
60+
61+
private class CustomConverter implements ConverterStrategy {
62+
@Override
63+
public String convert( String value, String name ) throws ConverterException {
64+
return value;
65+
}
66+
}
5467
}

0 commit comments

Comments
 (0)