|
1 | 1 | # 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). |
0 commit comments