Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
3fcfc67505
|
@ -0,0 +1,77 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>resteasy-tutorial</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<properties>
|
||||
<resteasy.version>3.0.14.Final</resteasy.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<finalName>RestEasyTutorial</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- core library -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-servlet-initializer</artifactId>
|
||||
<version>${resteasy.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-client</artifactId>
|
||||
<version>${resteasy.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Optional library -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jaxb-provider</artifactId>
|
||||
<version>${resteasy.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jackson-provider</artifactId>
|
||||
<version>${resteasy.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Junit Library -->
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
|
@ -0,0 +1,36 @@
|
|||
package com.baeldung.client;
|
||||
|
||||
import com.baeldung.model.Movie;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.List;
|
||||
|
||||
@Path("/movies")
|
||||
public interface ServicesInterface {
|
||||
|
||||
@GET
|
||||
@Path("/getinfo")
|
||||
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||
Movie movieByImdbId(@QueryParam("imdbId") String imdbId);
|
||||
|
||||
@GET
|
||||
@Path("/listmovies")
|
||||
@Produces({ "application/json" })
|
||||
List<Movie> listMovies();
|
||||
|
||||
@POST
|
||||
@Path("/addmovie")
|
||||
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||
Response addMovie(Movie movie);
|
||||
|
||||
@PUT
|
||||
@Path("/updatemovie")
|
||||
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||
Response updateMovie(Movie movie);
|
||||
|
||||
@DELETE
|
||||
@Path("/deletemovie")
|
||||
Response deleteMovie(@QueryParam("imdbId") String imdbID);
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package com.baeldung.model;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "movie", propOrder = { "imdbId", "title" })
|
||||
public class Movie {
|
||||
|
||||
protected String imdbId;
|
||||
protected String title;
|
||||
|
||||
public Movie(String imdbId, String title) {
|
||||
this.imdbId = imdbId;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public Movie() {}
|
||||
|
||||
public String getImdbId() {
|
||||
return imdbId;
|
||||
}
|
||||
|
||||
public void setImdbId(String imdbId) {
|
||||
this.imdbId = imdbId;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
|
||||
Movie movie = (Movie) o;
|
||||
|
||||
if (imdbId != null ? !imdbId.equals(movie.imdbId) : movie.imdbId != null)
|
||||
return false;
|
||||
return title != null ? title.equals(movie.title) : movie.title == null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = imdbId != null ? imdbId.hashCode() : 0;
|
||||
result = 31 * result + (title != null ? title.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Movie{" +
|
||||
"imdbId='" + imdbId + '\'' +
|
||||
", title='" + title + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package com.baeldung.server;
|
||||
|
||||
import com.baeldung.model.Movie;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Path("/movies")
|
||||
public class MovieCrudService {
|
||||
|
||||
private Map<String, Movie> inventory = new HashMap<String, Movie>();
|
||||
|
||||
@GET
|
||||
@Path("/getinfo")
|
||||
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||
public Movie movieByImdbId(@QueryParam("imdbId") String imdbId) {
|
||||
|
||||
System.out.println("*** Calling getinfo for a given ImdbID***");
|
||||
|
||||
if (inventory.containsKey(imdbId)) {
|
||||
return inventory.get(imdbId);
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/addmovie")
|
||||
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||
public Response addMovie(Movie movie) {
|
||||
|
||||
System.out.println("*** Calling addMovie ***");
|
||||
|
||||
if (null != inventory.get(movie.getImdbId())) {
|
||||
return Response.status(Response.Status.NOT_MODIFIED).entity("Movie is Already in the database.").build();
|
||||
}
|
||||
|
||||
inventory.put(movie.getImdbId(), movie);
|
||||
return Response.status(Response.Status.CREATED).build();
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("/updatemovie")
|
||||
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||
public Response updateMovie(Movie movie) {
|
||||
|
||||
System.out.println("*** Calling updateMovie ***");
|
||||
|
||||
if (null == inventory.get(movie.getImdbId())) {
|
||||
return Response.status(Response.Status.NOT_MODIFIED).entity("Movie is not in the database.\nUnable to Update").build();
|
||||
}
|
||||
|
||||
inventory.put(movie.getImdbId(), movie);
|
||||
return Response.status(Response.Status.OK).build();
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("/deletemovie")
|
||||
public Response deleteMovie(@QueryParam("imdbId") String imdbId) {
|
||||
|
||||
System.out.println("*** Calling deleteMovie ***");
|
||||
|
||||
if (null == inventory.get(imdbId)) {
|
||||
return Response.status(Response.Status.NOT_FOUND).entity("Movie is not in the database.\nUnable to Delete").build();
|
||||
}
|
||||
|
||||
inventory.remove(imdbId);
|
||||
return Response.status(Response.Status.OK).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/listmovies")
|
||||
@Produces({ "application/json" })
|
||||
public List<Movie> listMovies() {
|
||||
|
||||
return inventory.values().stream().collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.baeldung.server;
|
||||
|
||||
import javax.ws.rs.ApplicationPath;
|
||||
import javax.ws.rs.core.Application;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@ApplicationPath("/rest")
|
||||
public class RestEasyServices extends Application {
|
||||
|
||||
private Set<Object> singletons = new HashSet<Object>();
|
||||
|
||||
public RestEasyServices() {
|
||||
singletons.add(new MovieCrudService());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Object> getSingletons() {
|
||||
return singletons;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Class<?>> getClasses() {
|
||||
return super.getClasses();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getProperties() {
|
||||
return super.getProperties();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<configuration scan="true" scanPeriod="10 seconds">
|
||||
|
||||
</configuration>
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0"?>
|
||||
<jboss-deployment-structure>
|
||||
<deployment>
|
||||
<exclude-subsystems>
|
||||
<subsystem name="resteasy"/>
|
||||
</exclude-subsystems>
|
||||
<exclusions>
|
||||
<module name="javaee.api"/><module name="javax.ws.rs.api"/>
|
||||
<module name="org.jboss.resteasy.resteasy-jaxrs"/>
|
||||
</exclusions>
|
||||
<local-last value="true"/>
|
||||
</deployment>
|
||||
</jboss-deployment-structure>
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 4.2//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_4_2.dtd">
|
||||
<jboss-web>
|
||||
</jboss-web>
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
|
||||
|
||||
<display-name>RestEasy Example</display-name>
|
||||
|
||||
<context-param>
|
||||
<param-name>resteasy.servlet.mapping.prefix</param-name>
|
||||
<param-value>/rest</param-value>
|
||||
</context-param>
|
||||
|
||||
</web-app>
|
|
@ -3,4 +3,8 @@
|
|||
## Core Java 8 Cookbooks and Examples
|
||||
|
||||
### Relevant Articles:
|
||||
// - [Java 8 – Powerful Comparison with Lambdas](http://www.baeldung.com/java-8-sort-lambda)
|
||||
// - [Java 8 – Powerful Comparison with Lambdas](http://www.baeldung.com/java-8-sort-lambda)
|
||||
- [Java – Directory Size](http://www.baeldung.com/java-folder-size)
|
||||
- [Java – Try with Resources](http://www.baeldung.com/java-try-with-resources)
|
||||
- [Lambda Expressions and Functional Interfaces: Tips and Best Practices](http://www.baeldung.com/java-8-lambda-expressions-tips)
|
||||
- [The Double Colon Operator in Java 8](http://www.baeldung.com/java-8-double-colon-operator)
|
||||
|
|
|
@ -6,4 +6,10 @@
|
|||
- [Immutable ArrayList in Java](http://www.baeldung.com/java-immutable-list)
|
||||
- [Java - Reading a Large File Efficiently](http://www.baeldung.com/java-read-lines-large-file)
|
||||
- [Java InputStream to String](http://www.baeldung.com/convert-input-stream-to-string)
|
||||
|
||||
- [Converting between an Array and a List in Java](http://www.baeldung.com/convert-array-to-list-and-list-to-array)
|
||||
- [Converting between an Array and a Set in Java](http://www.baeldung.com/convert-array-to-set-and-set-to-array)
|
||||
- [Converting between a List and a Set in Java](http://www.baeldung.com/convert-list-to-set-and-set-to-list)
|
||||
- [Convert a Map to an Array, List or Set in Java](http://www.baeldung.com/convert-map-values-to-array-list-set)
|
||||
- [Java – Write to File](http://www.baeldung.com/java-write-to-file)
|
||||
- [Java Scanner](http://www.baeldung.com/java-scanner)
|
||||
- [Java Timer](http://www.baeldung.com/java-timer-and-timertask)
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
|
||||
## GSON Cookbooks and Examples
|
||||
|
||||
### Relevant Articles:
|
||||
|
||||
### Relevant Articles:
|
||||
- [Gson Deserialization Cookbook](http://www.baeldung.com/gson-deserialization-guide)
|
||||
|
|
|
@ -7,7 +7,11 @@
|
|||
- [Guava Collections Cookbook](http://www.baeldung.com/guava-collections)
|
||||
- [Guava Ordering Cookbook](http://www.baeldung.com/guava-order)
|
||||
- [Guava Functional Cookbook](http://www.baeldung.com/guava-functions-predicates)
|
||||
|
||||
- [Hamcrest Collections Cookbook](http://www.baeldung.com/hamcrest-collections-arrays)
|
||||
|
||||
- [Partition a List in Java](http://www.baeldung.com/java-list-split)
|
||||
- [Filtering and Transforming Collections in Guava](http://www.baeldung.com/guava-filter-and-transform-a-collection)
|
||||
- [Guava – Join and Split Collections](http://www.baeldung.com/guava-joiner-and-splitter-tutorial)
|
||||
- [Guava – Write to File, Read from File](http://www.baeldung.com/guava-write-to-file-read-from-file)
|
||||
- [Guava – Lists](http://www.baeldung.com/guava-lists)
|
||||
- [Guava – Sets](http://www.baeldung.com/guava-sets)
|
||||
- [Guava – Maps](http://www.baeldung.com/guava-maps)
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
- [Guava Collections Cookbook](http://www.baeldung.com/guava-collections)
|
||||
- [Guava Ordering Cookbook](http://www.baeldung.com/guava-order)
|
||||
- [Guava Functional Cookbook](http://www.baeldung.com/guava-functions-predicates)
|
||||
|
||||
- [Hamcrest Collections Cookbook](http://www.baeldung.com/hamcrest-collections-arrays)
|
||||
|
||||
- [Partition a List in Java](http://www.baeldung.com/java-list-split)
|
||||
- [Guava 18: What’s New?](http://www.baeldung.com/whats-new-in-guava-18)
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>19.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-all</artifactId>
|
||||
<version>1.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.3</version>
|
||||
<configuration>
|
||||
<debug>true</debug>
|
||||
<optimize>true</optimize>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
<showDeprecation>true</showDeprecation>
|
||||
<showWarnings>true</showWarnings>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,36 @@
|
|||
package com.baeldung.guava.entity;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
|
||||
public class User{
|
||||
private long id;
|
||||
private String name;
|
||||
private int age;
|
||||
|
||||
public User(long id, String name, int age) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(User.class)
|
||||
.add("id", id)
|
||||
.add("name", name)
|
||||
.add("age", age)
|
||||
.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.baeldung.guava;
|
||||
|
||||
import com.google.common.base.CharMatcher;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class CharMatcherTest {
|
||||
@Test
|
||||
public void whenMatchingLetterOrString_ShouldReturnTrueForCorrectString() throws Exception {
|
||||
String inputString = "someString789";
|
||||
boolean result = CharMatcher.javaLetterOrDigit().matchesAllOf(inputString);
|
||||
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCollapsingString_ShouldReturnStringWithDashesInsteadOfWhitespaces() throws Exception {
|
||||
String inputPhoneNumber = "8 123 456 123";
|
||||
String result = CharMatcher.whitespace().collapseFrom(inputPhoneNumber, '-');
|
||||
|
||||
assertEquals("8-123-456-123", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCountingDigitsInString_ShouldReturnActualCountOfDigits() throws Exception {
|
||||
String inputPhoneNumber = "8 123 456 123";
|
||||
int result = CharMatcher.digit().countIn(inputPhoneNumber);
|
||||
|
||||
assertEquals(10, result);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package com.baeldung.guava;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.*;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
|
||||
import static org.hamcrest.core.AnyOf.anyOf;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class GuavaMiscUtilsTest {
|
||||
|
||||
@Test
|
||||
public void whenGettingLazyStackTrace_ListShouldBeReturned() throws Exception {
|
||||
IllegalArgumentException e = new IllegalArgumentException("Some argument is incorrect");
|
||||
|
||||
List<StackTraceElement> stackTraceElements = Throwables.lazyStackTrace(e);
|
||||
|
||||
assertTrue(stackTraceElements.size() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multisetShouldCountHitsOfMultipleDuplicateObjects() throws Exception {
|
||||
List<String> userNames = Arrays.asList("David", "Eugene", "Alex", "Alex", "David", "David", "David");
|
||||
|
||||
Multiset<String> userNamesMultiset = HashMultiset.create(userNames);
|
||||
|
||||
assertEquals(7, userNamesMultiset.size());
|
||||
assertEquals(4, userNamesMultiset.count("David"));
|
||||
assertEquals(2, userNamesMultiset.count("Alex"));
|
||||
assertEquals(1, userNamesMultiset.count("Eugene"));
|
||||
assertThat(userNamesMultiset.elementSet(), anyOf(containsInAnyOrder("Alex", "David", "Eugene")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAddingNewConnectedRange_RangesShouldBeMerged() throws Exception {
|
||||
RangeSet<Integer> rangeSet = TreeRangeSet.create();
|
||||
|
||||
rangeSet.add(Range.closed(1, 10));
|
||||
rangeSet.add(Range.closed(5, 15));
|
||||
rangeSet.add(Range.closedOpen(10, 17));
|
||||
|
||||
assertTrue(rangeSet.encloses(Range.closedOpen(1, 17)));
|
||||
assertTrue(rangeSet.encloses(Range.closed(2, 3)));
|
||||
assertTrue(rangeSet.contains(15));
|
||||
assertFalse(rangeSet.contains(17));
|
||||
assertEquals(1, rangeSet.asDescendingSetOfRanges().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cartesianProductShouldReturnAllPossibleCombinations() throws Exception {
|
||||
List<String> first = Lists.newArrayList("value1", "value2");
|
||||
List<String> second = Lists.newArrayList("value3", "value4");
|
||||
|
||||
List<List<String>> cartesianProduct = Lists.cartesianProduct(first, second);
|
||||
|
||||
List<String> pair1 = Lists.newArrayList("value2", "value3");
|
||||
List<String> pair2 = Lists.newArrayList("value2", "value4");
|
||||
List<String> pair3 = Lists.newArrayList("value1", "value3");
|
||||
List<String> pair4 = Lists.newArrayList("value1", "value4");
|
||||
|
||||
assertThat(cartesianProduct, anyOf(containsInAnyOrder(pair1, pair2, pair3, pair4)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multisetShouldRemoveOccurrencesOfSpecifiedObjects() throws Exception {
|
||||
Multiset<String> multisetToModify = HashMultiset.create();
|
||||
Multiset<String> occurrencesToRemove = HashMultiset.create();
|
||||
|
||||
multisetToModify.add("John");
|
||||
multisetToModify.add("Max");
|
||||
multisetToModify.add("Alex");
|
||||
|
||||
occurrencesToRemove.add("Alex");
|
||||
occurrencesToRemove.add("John");
|
||||
|
||||
Multisets.removeOccurrences(multisetToModify, occurrencesToRemove);
|
||||
|
||||
assertEquals(1, multisetToModify.size());
|
||||
assertTrue(multisetToModify.contains("Max"));
|
||||
assertFalse(multisetToModify.contains("John"));
|
||||
assertFalse(multisetToModify.contains("Alex"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.baeldung.guava;
|
||||
|
||||
import com.google.common.hash.HashCode;
|
||||
import com.google.common.hash.HashFunction;
|
||||
import com.google.common.hash.Hashing;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class HashingTest {
|
||||
@Test
|
||||
public void whenHashingInSha384_hashFunctionShouldBeReturned() throws Exception {
|
||||
int inputData = 15;
|
||||
|
||||
HashFunction hashFunction = Hashing.sha384();
|
||||
HashCode hashCode = hashFunction.hashInt(inputData);
|
||||
|
||||
assertEquals("0904b6277381dcfbdddd6b6c66e4e3e8f83d4690718d8e6f272c891f24773a12feaf8c449fa6e42240a621b2b5e3cda8",
|
||||
hashCode.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenConcatenatingHashFunction_concatenatedHashShouldBeReturned() throws Exception {
|
||||
int inputData = 15;
|
||||
|
||||
HashFunction hashFunction = Hashing.concatenating(Hashing.crc32(), Hashing.crc32());
|
||||
HashFunction crc32Function = Hashing.crc32();
|
||||
|
||||
HashCode hashCode = hashFunction.hashInt(inputData);
|
||||
HashCode crc32HashCode = crc32Function.hashInt(inputData);
|
||||
|
||||
assertEquals(crc32HashCode.toString() + crc32HashCode.toString(), hashCode.toString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.baeldung.guava;
|
||||
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class TypeTokenTest {
|
||||
@Test
|
||||
public void whenCheckingIsAssignableFrom_shouldReturnTrueEvenIfGenericIsSpecified() throws Exception {
|
||||
ArrayList<String> stringList = new ArrayList<>();
|
||||
ArrayList<Integer> intList = new ArrayList<>();
|
||||
boolean isAssignableFrom = stringList.getClass().isAssignableFrom(intList.getClass());
|
||||
|
||||
assertTrue(isAssignableFrom);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCheckingIsSupertypeOf_shouldReturnFalseIfGenericIsSpecified() throws Exception {
|
||||
TypeToken<ArrayList<String>> listString = new TypeToken<ArrayList<String>>() {
|
||||
};
|
||||
TypeToken<ArrayList<Integer>> integerString = new TypeToken<ArrayList<Integer>>() {
|
||||
};
|
||||
|
||||
boolean isSupertypeOf = listString.isSupertypeOf(integerString);
|
||||
|
||||
assertFalse(isSupertypeOf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCheckingIsSubtypeOf_shouldReturnTrueIfClassIsExtendedFrom() throws Exception {
|
||||
TypeToken<ArrayList<String>> stringList = new TypeToken<ArrayList<String>>() {
|
||||
};
|
||||
TypeToken<List> list = new TypeToken<List>() {
|
||||
};
|
||||
|
||||
boolean isSubtypeOf = stringList.isSubtypeOf(list);
|
||||
|
||||
assertTrue(isSubtypeOf);
|
||||
}
|
||||
}
|
|
@ -5,12 +5,15 @@
|
|||
|
||||
### Relevant Articles:
|
||||
|
||||
- [HttpClient 4 – Send Custom Cookie](http://www.baeldung.com/httpclient-4-cookies)
|
||||
- [HttpClient 4 – Get the Status Code](http://www.baeldung.com/httpclient-status-code)
|
||||
- [HttpClient 4 – Cancel / Abort Request](http://www.baeldung.com/httpclient-cancel-request)
|
||||
- [HttpClient 4 – Send Custom Cookie](http://www.baeldung.com/httpclient-4-cookies)
|
||||
- [HttpClient 4 – Get the Status Code](http://www.baeldung.com/httpclient-status-code)
|
||||
- [HttpClient 4 – Cancel / Abort Request](http://www.baeldung.com/httpclient-cancel-request)
|
||||
- [HttpClient 4 Cookbook](http://www.baeldung.com/httpclient4)
|
||||
- [Unshorten URLs with HttpClient](http://www.baeldung.com/unshorten-url-httpclient)
|
||||
- [HttpClient with SSL](http://www.baeldung.com/httpclient-ssl)
|
||||
- [HttpClient 4 – Follow Redirects for POST](http://www.baeldung.com/httpclient-redirect-on-http-post)
|
||||
- [HttpClient – Set Custom Header](http://www.baeldung.com/httpclient-custom-http-header)
|
||||
- [HttpClient 4 – Follow Redirects for POST](http://www.baeldung.com/httpclient-redirect-on-http-post)
|
||||
- [HttpClient – Set Custom Header](http://www.baeldung.com/httpclient-custom-http-header)
|
||||
- [HttpClient Basic Authentication](http://www.baeldung.com/httpclient-4-basic-authentication)
|
||||
- [Multipart Upload with HttpClient 4](http://www.baeldung.com/httpclient-multipart-upload)
|
||||
- [HttpAsyncClient Tutorial](http://www.baeldung.com/httpasyncclient-tutorial)
|
||||
- [HttpClient 4 Tutorial](http://www.baeldung.com/httpclient-guide)
|
||||
|
|
|
@ -4,9 +4,15 @@
|
|||
|
||||
### Relevant Articles:
|
||||
- [Jackson Ignore Properties on Marshalling](http://www.baeldung.com/jackson-ignore-properties-on-serialization)
|
||||
- [Jackson – Unmarshall to Collection/Array](http://www.baeldung.com/jackson-collection-array)
|
||||
- [Jackson – Unmarshall to Collection/Array](http://www.baeldung.com/jackson-collection-array)
|
||||
- [Jackson Unmarshalling json with Unknown Properties](http://www.baeldung.com/jackson-deserialize-json-unknown-properties)
|
||||
- [Jackson – Custom Serializer](http://www.baeldung.com/jackson-custom-serialization)
|
||||
- [Jackson – Custom Deserializer](http://www.baeldung.com/jackson-deserialization)
|
||||
|
||||
|
||||
- [Jackson – Custom Serializer](http://www.baeldung.com/jackson-custom-serialization)
|
||||
- [Jackson – Custom Deserializer](http://www.baeldung.com/jackson-deserialization)
|
||||
- [Jackson Exceptions – Problems and Solutions](http://www.baeldung.com/jackson-exception)
|
||||
- [Jackson Date](http://www.baeldung.com/jackson-serialize-dates)
|
||||
- [Jackson – Bidirectional Relationships](http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion)
|
||||
- [Jackson JSON Tutorial](http://www.baeldung.com/jackson)
|
||||
- [Jackson – Working with Maps and nulls](http://www.baeldung.com/jackson-map-null-values-or-null-key)
|
||||
- [Jackson – Decide What Fields Get Serialized/Deserializaed](http://www.baeldung.com/jackson-field-serializable-deserializable-or-not)
|
||||
- [A Guide to Jackson Annotations](http://www.baeldung.com/jackson-annotations)
|
||||
- [Working with Tree Model Nodes in Jackson](http://www.baeldung.com/jackson-json-node-tree-model)
|
||||
|
|
|
@ -140,7 +140,7 @@
|
|||
<mysql-connector-java.version>5.1.35</mysql-connector-java.version>
|
||||
|
||||
<!-- marshalling -->
|
||||
<jackson.version>2.5.5</jackson.version>
|
||||
<jackson.version>2.7.1-1</jackson.version>
|
||||
|
||||
<!-- logging -->
|
||||
<org.slf4j.version>1.7.13</org.slf4j.version>
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package org.baeldung.jackson.dynamicIgnore;
|
||||
|
||||
|
||||
public class Address implements Hidable {
|
||||
private String city;
|
||||
private String country;
|
||||
private boolean hidden;
|
||||
|
||||
public Address(final String city, final String country, final boolean hidden) {
|
||||
super();
|
||||
this.city = city;
|
||||
this.country = country;
|
||||
this.hidden = hidden;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(final String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String getCountry() {
|
||||
return country;
|
||||
}
|
||||
|
||||
public void setCountry(final String country) {
|
||||
this.country = country;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHidden() {
|
||||
return hidden;
|
||||
}
|
||||
|
||||
public void setHidden(final boolean hidden) {
|
||||
this.hidden = hidden;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package org.baeldung.jackson.dynamicIgnore;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
|
||||
@JsonIgnoreProperties("hidden")
|
||||
public interface Hidable {
|
||||
boolean isHidden();
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package org.baeldung.jackson.dynamicIgnore;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
|
||||
public class HidableSerializer extends JsonSerializer<Hidable> {
|
||||
|
||||
private JsonSerializer<Object> defaultSerializer;
|
||||
|
||||
public HidableSerializer(final JsonSerializer<Object> serializer) {
|
||||
defaultSerializer = serializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(final Hidable value, final JsonGenerator jgen, final SerializerProvider provider) throws IOException, JsonProcessingException {
|
||||
if (value.isHidden())
|
||||
return;
|
||||
defaultSerializer.serialize(value, jgen, provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty(final SerializerProvider provider, final Hidable value) {
|
||||
return (value == null || value.isHidden());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package org.baeldung.jackson.dynamicIgnore;
|
||||
|
||||
|
||||
public class Person implements Hidable {
|
||||
private String name;
|
||||
private Address address;
|
||||
private boolean hidden;
|
||||
|
||||
public Person(final String name, final Address address, final boolean hidden) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
this.hidden = hidden;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(final Address address) {
|
||||
this.address = address;
|
||||
}
|
||||
@Override
|
||||
public boolean isHidden() {
|
||||
return hidden;
|
||||
}
|
||||
|
||||
public void setHidden(final boolean hidden) {
|
||||
this.hidden = hidden;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package org.baeldung.jackson.test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.baeldung.jackson.dynamicIgnore.Address;
|
||||
import org.baeldung.jackson.dynamicIgnore.Hidable;
|
||||
import org.baeldung.jackson.dynamicIgnore.HidableSerializer;
|
||||
import org.baeldung.jackson.dynamicIgnore.Person;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.BeanDescription;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationConfig;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
|
||||
|
||||
public class JacksonDynamicIgnoreTest {
|
||||
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mapper.setSerializationInclusion(Include.NON_EMPTY);
|
||||
mapper.registerModule(new SimpleModule() {
|
||||
@Override
|
||||
public void setupModule(final SetupContext context) {
|
||||
super.setupModule(context);
|
||||
context.addBeanSerializerModifier(new BeanSerializerModifier() {
|
||||
@Override
|
||||
public JsonSerializer<?> modifySerializer(final SerializationConfig config, final BeanDescription beanDesc, final JsonSerializer<?> serializer) {
|
||||
if (Hidable.class.isAssignableFrom(beanDesc.getBeanClass())) {
|
||||
return new HidableSerializer((JsonSerializer<Object>) serializer);
|
||||
}
|
||||
return serializer;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenNotHidden_thenCorrect() throws JsonProcessingException {
|
||||
final Address ad = new Address("ny", "usa", false);
|
||||
final Person person = new Person("john", ad, false);
|
||||
final String result = mapper.writeValueAsString(person);
|
||||
|
||||
assertTrue(result.contains("name"));
|
||||
assertTrue(result.contains("john"));
|
||||
assertTrue(result.contains("address"));
|
||||
assertTrue(result.contains("usa"));
|
||||
|
||||
System.out.println("Not Hidden = " + result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAddressHidden_thenCorrect() throws JsonProcessingException {
|
||||
final Address ad = new Address("ny", "usa", true);
|
||||
final Person person = new Person("john", ad, false);
|
||||
final String result = mapper.writeValueAsString(person);
|
||||
|
||||
assertTrue(result.contains("name"));
|
||||
assertTrue(result.contains("john"));
|
||||
assertFalse(result.contains("address"));
|
||||
assertFalse(result.contains("usa"));
|
||||
|
||||
System.out.println("Address Hidden = " + result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAllHidden_thenCorrect() throws JsonProcessingException {
|
||||
final Address ad = new Address("ny", "usa", false);
|
||||
final Person person = new Person("john", ad, true);
|
||||
final String result = mapper.writeValueAsString(person);
|
||||
|
||||
assertTrue(result.length() == 0);
|
||||
|
||||
System.out.println("All Hidden = " + result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSerializeList_thenCorrect() throws JsonProcessingException {
|
||||
final Address ad1 = new Address("tokyo", "jp", true);
|
||||
final Address ad2 = new Address("london", "uk", false);
|
||||
final Address ad3 = new Address("ny", "usa", false);
|
||||
final Person p1 = new Person("john", ad1, false);
|
||||
final Person p2 = new Person("tom", ad2, true);
|
||||
final Person p3 = new Person("adam", ad3, false);
|
||||
|
||||
final String result = mapper.writeValueAsString(Arrays.asList(p1, p2, p3));
|
||||
|
||||
System.out.println(result);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
=========
|
||||
|
||||
## Mockito Mocks into Spring Beans
|
||||
|
||||
|
||||
### Relevant Articles:
|
||||
- [Injecting Mockito Mocks into Spring Beans](http://www.baeldung.com/injecting-mocks-in-spring)
|
|
@ -6,4 +6,5 @@
|
|||
### Relevant Articles:
|
||||
- [Mockito Verify Cookbook](http://www.baeldung.com/mockito-verify)
|
||||
- [Mockito When/Then Cookbook](http://www.baeldung.com/mockito-behavior)
|
||||
|
||||
- [Mockito – Using Spies](http://www.baeldung.com/mockito-spy)
|
||||
- [Mockito – @Mock, @Spy, @Captor and @InjectMocks](http://www.baeldung.com/mockito-annotations)
|
||||
|
|
|
@ -6,4 +6,6 @@ This project is used to replicate Spring Exceptions only.
|
|||
|
||||
|
||||
### Relevant articles:
|
||||
- [Properties with Spring](http://www.baeldung.com/2012/02/06/properties-with-spring) - checkout the `org.baeldung.properties` package for all scenarios of properties injection and usage
|
||||
- [Properties with Spring](http://www.baeldung.com/2012/02/06/properties-with-spring) - checkout the `org.baeldung.properties` package for all scenarios of properties injection and usage
|
||||
- [Spring Profiles](http://www.baeldung.com/spring-profiles)
|
||||
- [A Spring Custom Annotation for a Better DAO](http://www.baeldung.com/spring-annotation-bean-pre-processor)
|
||||
|
|
|
@ -1 +1,7 @@
|
|||
=========
|
||||
|
||||
## Spring Batch
|
||||
|
||||
|
||||
### Relevant Articles:
|
||||
- [Introduction to Spring Batch](http://www.baeldung.com/introduction-to-spring-batch)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
### Relevant Articles:
|
||||
- [Introduction to Spring Data Cassandra](http://www.baeldung.com/spring-data-cassandra-tutorial)
|
||||
- [Using the CassandraTemplate from Spring Data](http://www.baeldung.com/spring-data-cassandratemplate-cqltemplate)
|
||||
|
||||
### Build the Project with Tests Running
|
||||
```
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>spring-data-elasticsearch</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.springframework.ide.eclipse.core.springbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.springframework.ide.eclipse.core.springnature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -0,0 +1,12 @@
|
|||
## Spring Data Elasticsearch
|
||||
|
||||
### Build the Project with Tests Running
|
||||
```
|
||||
mvn clean install
|
||||
```
|
||||
|
||||
### Run Tests Directly
|
||||
```
|
||||
mvn test
|
||||
```
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.baeldung</groupId>
|
||||
<artifactId>spring-data-elasticsearch</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>spring-data-elasticsearch</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<org.springframework.data.version>1.3.2.RELEASE</org.springframework.data.version>
|
||||
<org.springframework.version>4.2.2.RELEASE</org.springframework.version>
|
||||
<junit.version>4.11</junit.version>
|
||||
<org.slf4j.version>1.7.12</org.slf4j.version>
|
||||
<logback.version>1.1.3</logback.version>
|
||||
<elasticsearch.version>1.3.2.RELEASE</elasticsearch.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>${org.springframework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit-dep</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>${org.springframework.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-elasticsearch</artifactId>
|
||||
<version>${elasticsearch.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${org.slf4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>${org.slf4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>log4j-over-slf4j</artifactId>
|
||||
<version>${org.slf4j.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,53 @@
|
|||
package com.baeldung.spring.data.es.config;
|
||||
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.node.NodeBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
@Configuration
|
||||
@EnableElasticsearchRepositories(basePackages = "com.baeldung.repository")
|
||||
@ComponentScan(basePackages = {"com.baeldung.spring.data.es.service"})
|
||||
public class Config {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(Config.class);
|
||||
|
||||
@Bean
|
||||
public NodeBuilder nodeBuilder() {
|
||||
return new NodeBuilder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ElasticsearchOperations elasticsearchTemplate() {
|
||||
|
||||
try {
|
||||
Path tmpDir = Files.createTempDirectory(Paths.get(System.getProperty("java.io.tmpdir")), "elasticsearch_data");
|
||||
|
||||
ImmutableSettings.Builder elasticsearchSettings = ImmutableSettings.settingsBuilder()
|
||||
.put("http.enabled", "false")
|
||||
.put("path.data", tmpDir.toAbsolutePath().toString());
|
||||
|
||||
logger.debug(tmpDir.toAbsolutePath().toString());
|
||||
|
||||
return new ElasticsearchTemplate(nodeBuilder()
|
||||
.local(true)
|
||||
.settings(elasticsearchSettings.build())
|
||||
.node()
|
||||
.client());
|
||||
} catch (IOException ioex) {
|
||||
logger.error("Cannot create temp dir", ioex);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.spring.data.es.dao;
|
||||
|
||||
import com.baeldung.spring.data.es.model.Article;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.elasticsearch.annotations.Query;
|
||||
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
|
||||
|
||||
public interface ArticleRepository extends ElasticsearchRepository<Article, String> {
|
||||
|
||||
Page<Article> findByAuthorsName(String name, Pageable pageable);
|
||||
|
||||
@Query("{\"bool\": {\"must\": [{\"match\": {\"authors.name\": \"?0\"}}]}}")
|
||||
Page<Article> findByAuthorsNameUsingCustomQuery(String name, Pageable pageable);
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package com.baeldung.spring.data.es.model;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.annotations.Field;
|
||||
import org.springframework.data.elasticsearch.annotations.FieldIndex;
|
||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Document(indexName = "blog", type = "article")
|
||||
public class Article {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
@Field(type = FieldType.String, index = FieldIndex.not_analyzed)
|
||||
private String title;
|
||||
@Field(type = FieldType.Nested)
|
||||
private List<Author> authors;
|
||||
|
||||
public Article() {
|
||||
}
|
||||
|
||||
public Article(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public List<Author> getAuthors() {
|
||||
return authors;
|
||||
}
|
||||
|
||||
public void setAuthors(List<Author> authors) {
|
||||
this.authors = authors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Article{" +
|
||||
"id='" + id + '\'' +
|
||||
", title='" + title + '\'' +
|
||||
", authors=" + authors +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.baeldung.spring.data.es.model;
|
||||
|
||||
public class Author {
|
||||
|
||||
private String name;
|
||||
|
||||
public Author() {
|
||||
}
|
||||
|
||||
public Author(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Author{" +
|
||||
"name='" + name + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.spring.data.es.repository;
|
||||
|
||||
import com.baeldung.spring.data.es.model.Article;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.elasticsearch.annotations.Query;
|
||||
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
|
||||
|
||||
public interface ArticleRepository extends ElasticsearchRepository<Article, String> {
|
||||
|
||||
Page<Article> findByAuthorsName(String name, Pageable pageable);
|
||||
|
||||
@Query("{\"bool\": {\"must\": [{\"match\": {\"authors.name\": \"?0\"}}]}}")
|
||||
Page<Article> findByAuthorsNameUsingCustomQuery(String name, Pageable pageable);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.spring.data.es.service;
|
||||
|
||||
import com.baeldung.spring.data.es.model.Article;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
public interface ArticleService {
|
||||
Article save(Article article);
|
||||
Article findOne(String id);
|
||||
Iterable<Article> findAll();
|
||||
Page<Article> findByAuthorName(String name, Pageable pageable);
|
||||
Page<Article> findByAuthorNameUsingCustomQuery(String name, Pageable pageable);
|
||||
long count();
|
||||
void delete(Article article);
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package com.baeldung.spring.data.es.service;
|
||||
|
||||
import com.baeldung.spring.data.es.repository.ArticleRepository;
|
||||
import com.baeldung.spring.data.es.model.Article;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class ArticleServiceImpl implements ArticleService {
|
||||
|
||||
private ArticleRepository articleRepository;
|
||||
|
||||
@Autowired
|
||||
public void setArticleRepository(ArticleRepository articleRepository) {
|
||||
this.articleRepository = articleRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Article save(Article article) {
|
||||
return articleRepository.save(article);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Article findOne(String id) {
|
||||
return articleRepository.findOne(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Article> findAll() {
|
||||
return articleRepository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Article> findByAuthorName(String name, Pageable pageable) {
|
||||
return articleRepository.findByAuthorsName(name, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Article> findByAuthorNameUsingCustomQuery(String name, Pageable pageable) {
|
||||
return articleRepository.findByAuthorsNameUsingCustomQuery(name, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
return articleRepository.count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Article article) {
|
||||
articleRepository.delete(article);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>elasticsearch - %date [%thread] %-5level %logger{36} - %message%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework" level="WARN" />
|
||||
<logger name="com.baeldung.config" level="DEBUG" />
|
||||
|
||||
<!-- in order to debug some marshalling issues, this needs to be TRACE -->
|
||||
<logger name="org.springframework.web.servlet.mvc" level="WARN" />
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
|
@ -0,0 +1,129 @@
|
|||
package com.baeldung.spring.data.es;
|
||||
|
||||
import com.baeldung.spring.data.es.config.Config;
|
||||
import com.baeldung.spring.data.es.model.Article;
|
||||
import com.baeldung.spring.data.es.model.Author;
|
||||
import com.baeldung.spring.data.es.service.ArticleService;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
||||
import org.springframework.data.elasticsearch.core.query.SearchQuery;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.support.AnnotationConfigContextLoader;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.elasticsearch.index.query.FilterBuilders.regexpFilter;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = {Config.class}, loader = AnnotationConfigContextLoader.class)
|
||||
public class ElasticSearchTest {
|
||||
|
||||
@Autowired
|
||||
private ElasticsearchTemplate elasticsearchTemplate;
|
||||
@Autowired
|
||||
private ArticleService articleService;
|
||||
|
||||
private final Author johnSmith = new Author("John Smith");
|
||||
private final Author johnDoe = new Author("John Doe");
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
elasticsearchTemplate.deleteIndex(Article.class);
|
||||
elasticsearchTemplate.createIndex(Article.class);
|
||||
|
||||
Article article = new Article("Spring Data Elasticsearch");
|
||||
article.setAuthors(asList(johnSmith, johnDoe));
|
||||
articleService.save(article);
|
||||
|
||||
article = new Article("Search engines");
|
||||
article.setAuthors(asList(johnDoe));
|
||||
articleService.save(article);
|
||||
|
||||
article = new Article("Second Article About Elasticsearch");
|
||||
article.setAuthors(asList(johnSmith));
|
||||
articleService.save(article);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenArticleService_whenSaveArticle_thenIdIsAssigned() {
|
||||
List<Author> authors = asList(
|
||||
new Author("John Smith"), johnDoe);
|
||||
|
||||
Article article = new Article("Making Search Elastic");
|
||||
article.setAuthors(authors);
|
||||
|
||||
article = articleService.save(article);
|
||||
assertNotNull(article.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenPersistedArticles_whenSearchByAuthorsName_thenRightFound() {
|
||||
|
||||
Page<Article> articleByAuthorName = articleService.findByAuthorName(johnSmith.getName(), new PageRequest(0, 10));
|
||||
assertEquals(2L, articleByAuthorName.getTotalElements());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCustomQuery_whenSearchByAuthorsName_thenArticleIsFound() {
|
||||
|
||||
Page<Article> articleByAuthorName = articleService.findByAuthorNameUsingCustomQuery("John Smith", new PageRequest(0, 10));
|
||||
assertEquals(3L, articleByAuthorName.getTotalElements());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void givenPersistedArticles_whenUseRegexQuery_thenRightArticlesFound() {
|
||||
|
||||
SearchQuery searchQuery = new NativeSearchQueryBuilder()
|
||||
.withFilter(regexpFilter("title", ".*data.*"))
|
||||
.build();
|
||||
List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
|
||||
|
||||
assertEquals(1, articles.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSavedDoc_whenTitleUpdated_thenCouldFindByUpdatedTitle() {
|
||||
SearchQuery searchQuery = new NativeSearchQueryBuilder()
|
||||
.withQuery(fuzzyQuery("title", "serch"))
|
||||
.build();
|
||||
List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
|
||||
|
||||
assertEquals(1, articles.size());
|
||||
|
||||
Article article = articles.get(0);
|
||||
final String newTitle = "Getting started with Search Engines";
|
||||
article.setTitle(newTitle);
|
||||
articleService.save(article);
|
||||
|
||||
assertEquals(newTitle, articleService.findOne(article.getId()).getTitle());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSavedDoc_whenDelete_thenRemovedFromIndex() {
|
||||
|
||||
final String articleTitle = "Spring Data Elasticsearch";
|
||||
|
||||
SearchQuery searchQuery = new NativeSearchQueryBuilder()
|
||||
.withQuery(matchQuery("title", articleTitle).minimumShouldMatch("75%"))
|
||||
.build();
|
||||
List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
|
||||
assertEquals(1, articles.size());
|
||||
final long count = articleService.count();
|
||||
|
||||
articleService.delete(articles.get(0));
|
||||
|
||||
assertEquals(count - 1, articleService.count());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
=========
|
||||
|
||||
## Spring Data MongoDB
|
||||
|
||||
|
||||
### Relevant Articles:
|
||||
- [A Guide to Queries in Spring Data MongoDB](http://www.baeldung.com/queries-in-spring-data-mongodb)
|
||||
- [Spring Data MongoDB – Indexes, Annotations and Converters](http://www.baeldung.com/spring-data-mongodb-index-annotations-converter)
|
||||
- [Custom Cascading in Spring Data MongoDB](http://www.baeldung.com/cascading-with-dbref-and-lifecycle-events-in-spring-data-mongodb)
|
||||
- [GridFS in Spring Data MongoDB](http://www.baeldung.com/spring-data-mongodb-gridfs)
|
||||
- [Introduction to Spring Data MongoDB](http://www.baeldung.com/spring-data-mongodb-tutorial)
|
|
@ -0,0 +1,7 @@
|
|||
=========
|
||||
|
||||
## Using FreeMarker in Spring MVC
|
||||
|
||||
|
||||
### Relevant Articles:
|
||||
- [Introduction to Using FreeMarker in Spring MVC](http://www.baeldung.com/freemarker-in-spring-mvc-tutorial)
|
|
@ -5,6 +5,9 @@
|
|||
### Relevant Articles:
|
||||
- [Hibernate 4 with Spring](http://www.baeldung.com/hibernate-4-spring)
|
||||
- [The DAO with Spring 3 and Hibernate](http://www.baeldung.com/2011/12/02/the-persistence-layer-with-spring-3-1-and-hibernate/)
|
||||
- [Hibernate Pagination](http://www.baeldung.com/hibernate-pagination)
|
||||
- [Sorting with Hibernate](http://www.baeldung.com/hibernate-sort)
|
||||
- [Auditing with JPA, Hibernate, and Spring Data JPA](http://www.baeldung.com/database-auditing-jpa)
|
||||
|
||||
|
||||
### Quick Start
|
||||
|
|
|
@ -7,3 +7,6 @@
|
|||
- [Spring 3 and JPA with Hibernate](http://www.baeldung.com/2011/12/13/the-persistence-layer-with-spring-3-1-and-jpa/)
|
||||
- [Transactions with Spring 3 and JPA](http://www.baeldung.com/2011/12/26/transaction-configuration-with-jpa-and-spring-3-1/)
|
||||
- [The DAO with JPA and Spring](http://www.baeldung.com/spring-dao-jpa)
|
||||
- [JPA Pagination](http://www.baeldung.com/jpa-pagination)
|
||||
- [Sorting with JPA](http://www.baeldung.com/jpa-sort)
|
||||
- [Spring JPA – Multiple Databases](http://www.baeldung.com/spring-data-jpa-multiple-databases)
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd"
|
||||
>
|
||||
|
||||
<http access-denied-page="/access-denied.html" use-expressions="true">
|
||||
<intercept-url pattern="/access-denied*" access="hasAnyRole('ROLE_LOCATION_WRITE','ROLE_POLYGON_WRITE')"/>
|
||||
<intercept-url pattern="/admin/**" access="hasAnyRole('ROLE_ADMIN')"/>
|
||||
<intercept-url pattern="/organization/**" access="hasAnyRole('ROLE_ORGANIZATION')"/>
|
||||
<intercept-url pattern="/location/edit*" access="hasAnyRole('ROLE_LOCATION_WRITE')"/>
|
||||
<intercept-url pattern="/location/view*" access="permitAll"/>
|
||||
|
||||
<intercept-url pattern="/login*" access="isAnonymous()"/>
|
||||
<intercept-url pattern="/register*" access="isAnonymous()"/>
|
||||
<intercept-url pattern="/login-denied/**" access="isAnonymous()"/>
|
||||
|
||||
<intercept-url pattern="/**" access="permitAll"/>
|
||||
|
||||
<form-login login-page='/login.html' default-target-url="/" always-use-default-target="false" authentication-failure-url="/login.html?error=true"/>
|
||||
|
||||
<logout/>
|
||||
|
||||
<anonymous/>
|
||||
|
||||
<session-management invalid-session-url="/">
|
||||
<concurrency-control max-sessions="1"/>
|
||||
</session-management>
|
||||
</http>
|
||||
|
||||
<authentication-manager alias="authenticationManager" erase-credentials="false">
|
||||
<authentication-provider ref="restAuthenticationProvider"/>
|
||||
</authentication-manager>
|
||||
|
||||
</beans:beans>
|
|
@ -0,0 +1,6 @@
|
|||
=========
|
||||
|
||||
## Java Web Application
|
||||
|
||||
### Relevant Articles:
|
||||
- [JSON API in a Java Web Application](http://www.baeldung.com/json-api-java-spring-web-app)
|
|
@ -4,3 +4,7 @@
|
|||
|
||||
|
||||
### Relevant Articles:
|
||||
- [Spring Bean Annotations](http://www.baeldung.com/spring-bean-annotations)
|
||||
- [Introduction to Pointcut Expressions in Spring](http://www.baeldung.com/spring-aop-pointcut-tutorial)
|
||||
- [Introduction to Advice Types in Spring](http://www.baeldung.com/spring-aop-advice-tutorial)
|
||||
- [A Guide to the ViewResolver in Spring MVC](http://www.baeldung.com/spring-mvc-view-resolver-tutorial)
|
||||
|
|
|
@ -7,3 +7,4 @@
|
|||
### Relevant Articles:
|
||||
- [Spring MVC Tutorial](http://www.baeldung.com/spring-mvc-tutorial)
|
||||
- [Servlet Session Timeout](http://www.baeldung.com/servlet-session-timeout)
|
||||
- [Basic Forms with Spring MVC](http://www.baeldung.com/spring-mvc-form-tutorial)
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>spring-openid</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.common.project.facet.core.builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.springframework.ide.eclipse.core.springbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.validation.validationbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
|
||||
<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
|
||||
<nature>org.springframework.ide.eclipse.core.springnature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
|
||||
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.baeldung</groupId>
|
||||
<artifactId>spring-openid</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<name>spring-openid</name>
|
||||
<description>Spring OpenID sample project</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.3.2.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.security.oauth</groupId>
|
||||
<artifactId>spring-security-oauth2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-jwt</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
</project>
|
|
@ -0,0 +1,51 @@
|
|||
package org.baeldung.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.oauth2.client.OAuth2ClientContext;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
|
||||
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
|
||||
|
||||
@Configuration
|
||||
@EnableOAuth2Client
|
||||
public class GoogleOpenIdConnectConfig {
|
||||
@Value("${google.clientId}")
|
||||
private String clientId;
|
||||
|
||||
@Value("${google.clientSecret}")
|
||||
private String clientSecret;
|
||||
|
||||
@Value("${google.accessTokenUri}")
|
||||
private String accessTokenUri;
|
||||
|
||||
@Value("${google.userAuthorizationUri}")
|
||||
private String userAuthorizationUri;
|
||||
|
||||
@Value("${google.redirectUri}")
|
||||
private String redirectUri;
|
||||
|
||||
@Bean
|
||||
public OAuth2ProtectedResourceDetails googleOpenId() {
|
||||
final AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
|
||||
details.setClientId(clientId);
|
||||
details.setClientSecret(clientSecret);
|
||||
details.setAccessTokenUri(accessTokenUri);
|
||||
details.setUserAuthorizationUri(userAuthorizationUri);
|
||||
details.setScope(Arrays.asList("openid", "email"));
|
||||
details.setPreEstablishedRedirectUri(redirectUri);
|
||||
details.setUseCurrentUri(false);
|
||||
return details;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OAuth2RestTemplate googleOpenIdTemplate(final OAuth2ClientContext clientContext) {
|
||||
final OAuth2RestTemplate template = new OAuth2RestTemplate(googleOpenId(), clientContext);
|
||||
return template;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package org.baeldung.config;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
public class HomeController {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@RequestMapping("/")
|
||||
@ResponseBody
|
||||
public final String home() {
|
||||
final String username = SecurityContextHolder.getContext().getAuthentication().getName();
|
||||
logger.info(username);
|
||||
return "Welcome, " + username;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package org.baeldung.config;
|
||||
|
||||
import org.baeldung.security.OpenIdConnectFilter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter;
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
private OAuth2RestTemplate restTemplate;
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web.ignoring().antMatchers("/resources/**");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OpenIdConnectFilter myFilter() {
|
||||
final OpenIdConnectFilter filter = new OpenIdConnectFilter("/google-login");
|
||||
filter.setRestTemplate(restTemplate);
|
||||
return filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.addFilterAfter(new OAuth2ClientContextFilter(), AbstractPreAuthenticatedProcessingFilter.class)
|
||||
.addFilterAfter(myFilter(), OAuth2ClientContextFilter.class)
|
||||
.httpBasic().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/google-login"))
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
// .antMatchers("/","/index*").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
;
|
||||
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package org.baeldung.config;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SpringOpenidApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringOpenidApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package org.baeldung.security;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.jwt.Jwt;
|
||||
import org.springframework.security.jwt.JwtHelper;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestOperations;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
||||
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
public class OpenIdConnectFilter extends AbstractAuthenticationProcessingFilter {
|
||||
public OAuth2RestOperations restTemplate;
|
||||
|
||||
public OpenIdConnectFilter(String defaultFilterProcessesUrl) {
|
||||
super(defaultFilterProcessesUrl);
|
||||
setAuthenticationManager(new NoopAuthenticationManager());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
|
||||
|
||||
OAuth2AccessToken accessToken;
|
||||
try {
|
||||
accessToken = restTemplate.getAccessToken();
|
||||
} catch (final OAuth2Exception e) {
|
||||
throw new BadCredentialsException("Could not obtain access token", e);
|
||||
}
|
||||
try {
|
||||
final String idToken = accessToken.getAdditionalInformation().get("id_token").toString();
|
||||
final Jwt tokenDecoded = JwtHelper.decode(idToken);
|
||||
System.out.println("===== : " + tokenDecoded.getClaims());
|
||||
|
||||
final Map<String, String> authInfo = new ObjectMapper().readValue(tokenDecoded.getClaims(), Map.class);
|
||||
|
||||
final OpenIdConnectUserDetails user = new OpenIdConnectUserDetails(authInfo, accessToken);
|
||||
return new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
|
||||
} catch (final InvalidTokenException e) {
|
||||
throw new BadCredentialsException("Could not obtain user details from token", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setRestTemplate(OAuth2RestTemplate restTemplate2) {
|
||||
restTemplate = restTemplate2;
|
||||
|
||||
}
|
||||
|
||||
private static class NoopAuthenticationManager implements AuthenticationManager {
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
throw new UnsupportedOperationException("No authentication should be done with this AuthenticationManager");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package org.baeldung.security;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
|
||||
public class OpenIdConnectUserDetails implements UserDetails {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String userId;
|
||||
private String username;
|
||||
private OAuth2AccessToken token;
|
||||
|
||||
public OpenIdConnectUserDetails(Map<String, String> userInfo, OAuth2AccessToken token) {
|
||||
this.userId = userInfo.get("sub");
|
||||
this.username = userInfo.get("email");
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public OAuth2AccessToken getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(OAuth2AccessToken token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
server.port=8081
|
||||
google.clientId=497324626536-d6fphsh1qpl2o6j2j66nukajrfqc0rtq.apps.googleusercontent.com
|
||||
google.clientSecret=vtueZycMsrRjjCjnY6JzbEZT
|
||||
google.accessTokenUri=https://www.googleapis.com/oauth2/v3/token
|
||||
google.userAuthorizationUri=https://accounts.google.com/o/oauth2/auth
|
||||
google.redirectUri=http://localhost:8081/google-login
|
|
@ -7,3 +7,4 @@
|
|||
- [Spring @RequestMapping](http://www.baeldung.com/spring-requestmapping)
|
||||
- [Http Message Converters with the Spring Framework](http://www.baeldung.com/spring-httpmessageconverter-rest)
|
||||
- [Redirect in Spring](http://www.baeldung.com/spring-redirect-and-forward)
|
||||
- [Returning Custom Status Codes from Spring Controllers](http://www.baeldung.com/spring-mvc-controller-custom-http-status-code)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ant.AntBuilderLaunchConfigurationType">
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_DISABLED_BUILDER" value="org.hibernate.eclipse.console.hibernateBuilder"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_DISABLED_BUILDER" value="org.eclipse.wst.jsdt.core.javascriptValidator"/>
|
||||
<mapAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||
</launchConfiguration>
|
|
@ -6,8 +6,13 @@
|
|||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
|
||||
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
|
||||
<triggers>full,incremental,</triggers>
|
||||
<arguments>
|
||||
<dictionary>
|
||||
<key>LaunchConfigHandle</key>
|
||||
<value><project>/.externalToolBuilders/org.eclipse.wst.jsdt.core.javascriptValidator.launch</value>
|
||||
</dictionary>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
|
@ -25,16 +30,6 @@
|
|||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.jboss.tools.jst.web.kb.kbbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.hibernate.eclipse.console.hibernateBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.validation.validationbuilder</name>
|
||||
<arguments>
|
||||
|
|
|
@ -5,8 +5,16 @@
|
|||
|
||||
### Relevant Articles:
|
||||
- [Spring Security Registration Tutorial](http://www.baeldung.com/spring-security-registration)
|
||||
|
||||
|
||||
- [The Registration Process With Spring Security](http://www.baeldung.com/registration-with-spring-mvc-and-spring-security)
|
||||
- [Registration – Activate a New Account by Email](http://www.baeldung.com/registration-verify-user-by-email)
|
||||
- [Registration with Spring Security – Password Encoding](http://www.baeldung.com/spring-security-registration-password-encoding-bcrypt)
|
||||
- [Spring Security – Roles and Privileges](http://www.baeldung.com/role-and-privilege-for-spring-security-registration)
|
||||
- [Prevent Brute Force Authentication Attempts with Spring Security](http://www.baeldung.com/spring-security-block-brute-force-authentication-attempts)
|
||||
- [Spring Security – Reset Your Password](http://www.baeldung.com/spring-security-registration-i-forgot-my-password)
|
||||
- [Spring Security Registration – Resend Verification Email](http://www.baeldung.com/spring-security-registration-verification-email)
|
||||
- [The Registration API becomes RESTful](http://www.baeldung.com/registration-restful-api)
|
||||
- [Registration – Password Strength and Rules](http://www.baeldung.com/registration-password-strength-and-rules)
|
||||
- [Updating your Password](http://www.baeldung.com/updating-your-password/)
|
||||
|
||||
### Build the Project
|
||||
```
|
||||
|
|
|
@ -269,7 +269,8 @@
|
|||
<version>${maven-surefire-plugin.version}</version>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<!-- <exclude>**/*ProductionTest.java</exclude> -->
|
||||
<exclude>**/*IntegrationTest.java</exclude>
|
||||
<exclude>**/*LiveTest.java</exclude>
|
||||
</excludes>
|
||||
<systemPropertyVariables>
|
||||
<!-- <provPersistenceTarget>h2</provPersistenceTarget> -->
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
### Relevant Article:
|
||||
- [Spring Security - security none, filters none, access permitAll](http://www.baeldung.com/security-none-filters-none-access-permitAll)
|
||||
- [Spring Security Basic Authentication](http://www.baeldung.com/spring-security-basic-authentication)
|
||||
|
||||
- [Intro to Spring Security LDAP](http://www.baeldung.com/spring-security-ldap)
|
||||
|
||||
### Notes
|
||||
- the project uses Spring Boot - simply run 'SampleLDAPApplication.java' to start up Spring Boot with a Tomcat container and embedded LDAP server.
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
|
||||
### Relevant Articles:
|
||||
- [Spring Security Persisted Remember Me]
|
||||
- [Spring Security Persisted Remember Me](http://www.baeldung.com/spring-security-persistent-remember-me)
|
||||
- [Spring Security Remember Me](http://www.baeldung.com/spring-security-remember-me)
|
||||
- [Redirect to different pages after Login with Spring Security](http://www.baeldung.com/spring_redirect_after_login)
|
||||
|
||||
|
|
|
@ -11,7 +11,16 @@
|
|||
- [ETags for REST with Spring](http://www.baeldung.com/2013/01/11/etags-for-rest-with-spring/)
|
||||
- [Error Handling for REST with Spring 3](http://www.baeldung.com/2013/01/31/exception-handling-for-rest-with-spring-3-2/)
|
||||
- [Integration Testing with the Maven Cargo plugin](http://www.baeldung.com/2011/10/16/how-to-set-up-integration-testing-with-the-maven-cargo-plugin/)
|
||||
|
||||
- [Introduction to Spring Data JPA](http://www.baeldung.com/2011/12/22/the-persistence-layer-with-spring-data-jpa/)
|
||||
- [Project Configuration with Spring](http://www.baeldung.com/2012/03/12/project-configuration-with-spring/)
|
||||
- [REST Query Language with Spring and JPA Criteria](http://www.baeldung.com/rest-search-language-spring-jpa-criteria)
|
||||
- [REST Query Language with Spring Data JPA Specifications](http://www.baeldung.com/rest-api-search-language-spring-data-specifications)
|
||||
- [REST Query Language with Spring Data JPA and QueryDSL](http://www.baeldung.com/rest-api-search-language-spring-data-querydsl)
|
||||
- [REST Query Language – Advanced Search Operations](http://www.baeldung.com/rest-api-query-search-language-more-operations)
|
||||
- [Metrics for your Spring REST API](http://www.baeldung.com/spring-rest-api-metrics)
|
||||
- [REST Query Language with RSQL](http://www.baeldung.com/rest-api-search-language-rsql-fiql)
|
||||
- [Spring RestTemplate Tutorial](http://www.baeldung.com/rest-template)
|
||||
- [A Guide to CSRF Protection in Spring Security](http://www.baeldung.com/spring-security-csrf)
|
||||
|
||||
### Build the Project
|
||||
```
|
||||
|
|
|
@ -5,3 +5,5 @@
|
|||
|
||||
### Relevant Articles:
|
||||
- [Spring REST Service Security](http://www.baeldung.com/2011/10/31/securing-a-restful-web-service-with-spring-security-3-1-part-3/)
|
||||
- [Setting Up Swagger 2 with a Spring REST API](http://www.baeldung.com/swagger-2-documentation-for-spring-rest-api)
|
||||
- [Custom Error Message Handling for REST API](http://www.baeldung.com/global-error-handler-in-a-spring-rest-api)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
=========
|
||||
|
||||
## Spring REST with a Zuul
|
||||
|
||||
|
||||
### Relevant Articles:
|
||||
- [Spring REST with a Zuul Proxy](http://www.baeldung.com/spring-rest-with-zuul-proxy)
|
Loading…
Reference in New Issue