Merge branch 'master' into BAEL-3760_Introduction_to_Takes
# Conflicts: # libraries-3/pom.xml
This commit is contained in:
commit
c82c692eb3
@ -73,6 +73,16 @@
|
||||
<version>${cache2k.version}</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.moshi</groupId>
|
||||
<artifactId>moshi</artifactId>
|
||||
<version>${moshi.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.moshi</groupId>
|
||||
<artifactId>moshi-adapters</artifactId>
|
||||
<version>${moshi.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jcabi</groupId>
|
||||
<artifactId>jcabi-aspects</artifactId>
|
||||
@ -191,7 +201,7 @@
|
||||
<cactoos.version>0.43</cactoos.version>
|
||||
<airline.version>2.7.2</airline.version>
|
||||
<cache2k.version>1.2.3.Final</cache2k.version>
|
||||
|
||||
<moshi.version>1.9.2</moshi.version>
|
||||
<jcabi-aspects.version>0.22.6</jcabi-aspects.version>
|
||||
<aspectjrt.version>1.9.2</aspectjrt.version>
|
||||
<jcabi-maven-plugin.version>0.14.1</jcabi-maven-plugin.version>
|
||||
|
@ -0,0 +1,105 @@
|
||||
package com.baeldung.moshi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.time.Instant;
|
||||
|
||||
import com.squareup.moshi.FromJson;
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.JsonQualifier;
|
||||
import com.squareup.moshi.Moshi;
|
||||
import com.squareup.moshi.ToJson;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.junit.Test;
|
||||
|
||||
public class AlternativeAdapterUnitTest {
|
||||
@Test
|
||||
public void whenSerializing_thenAlternativeAdapterUsed() {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.add(new EpochMillisAdapter())
|
||||
.build();
|
||||
JsonAdapter<Post> jsonAdapter = moshi.adapter(Post.class);
|
||||
|
||||
String json = jsonAdapter.toJson(new Post("Introduction to Moshi Json", "Baeldung", Instant.now()));
|
||||
System.out.println(json);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDeserializing_thenAlternativeAdapterUsed() throws IOException {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.add(new EpochMillisAdapter())
|
||||
.build();
|
||||
JsonAdapter<Post> jsonAdapter = moshi.adapter(Post.class);
|
||||
|
||||
String json = "{\"author\":\"Baeldung\",\"posted\":1582095269204,\"title\":\"Introduction to Moshi Json\"}";
|
||||
Post post = jsonAdapter.fromJson(json);
|
||||
System.out.println(post);
|
||||
|
||||
}
|
||||
|
||||
public static class Post {
|
||||
String title;
|
||||
String author;
|
||||
@EpochMillis Instant posted;
|
||||
|
||||
public Post() {
|
||||
}
|
||||
|
||||
public Post(String title, String author, Instant posted) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
this.posted = posted;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public Instant getPosted() {
|
||||
return posted;
|
||||
}
|
||||
|
||||
public void setPosted(Instant posted) {
|
||||
this.posted = posted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("title", title).append("author", author).append("posted", posted)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
|
||||
@JsonQualifier
|
||||
public @interface EpochMillis {
|
||||
}
|
||||
|
||||
public static class EpochMillisAdapter {
|
||||
@ToJson
|
||||
public Long toJson(@EpochMillis Instant input) {
|
||||
return input.toEpochMilli();
|
||||
}
|
||||
@FromJson
|
||||
@EpochMillis
|
||||
public Instant fromJson(Long input) {
|
||||
return Instant.ofEpochMilli(input);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.baeldung.moshi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.Moshi;
|
||||
import com.squareup.moshi.Types;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ArrayUnitTest {
|
||||
@Test
|
||||
public void whenSerializingList_thenJsonArrayProduced() {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.build();
|
||||
Type type = Types.newParameterizedType(List.class, String.class);
|
||||
JsonAdapter<List<String>> jsonAdapter = moshi.adapter(type);
|
||||
|
||||
String json = jsonAdapter.toJson(Arrays.asList("One", "Two", "Three"));
|
||||
System.out.println(json);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDeserializingJsonArray_thenListProduced() throws IOException {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.build();
|
||||
Type type = Types.newParameterizedType(List.class, String.class);
|
||||
JsonAdapter<List<String>> jsonAdapter = moshi.adapter(type);
|
||||
|
||||
String json = "[\"One\",\"Two\",\"Three\"]";
|
||||
List<String> result = jsonAdapter.fromJson(json);
|
||||
System.out.println(result);
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package com.baeldung.moshi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import com.squareup.moshi.FromJson;
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.Moshi;
|
||||
import com.squareup.moshi.ToJson;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ComplexAdapterUnitTest {
|
||||
@Test
|
||||
public void whenSerializing_thenCorrectJsonProduced() {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.add(new JsonDateTimeAdapter())
|
||||
.build();
|
||||
JsonAdapter<ZonedDateTime> jsonAdapter = moshi.adapter(ZonedDateTime.class);
|
||||
|
||||
String json = jsonAdapter.toJson(ZonedDateTime.now());
|
||||
System.out.println(json);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDeserializing_thenCorrectJsonConsumed() throws IOException {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.add(new JsonDateTimeAdapter())
|
||||
.build();
|
||||
JsonAdapter<ZonedDateTime> jsonAdapter = moshi.adapter(ZonedDateTime.class);
|
||||
|
||||
String json = "{\"date\":\"2020-02-17\",\"time\":\"07:53:27.064\",\"timezone\":\"Europe/London\"}";
|
||||
ZonedDateTime now = jsonAdapter.fromJson(json);
|
||||
System.out.println(now);
|
||||
|
||||
}
|
||||
|
||||
public static class JsonDateTimeAdapter {
|
||||
@ToJson
|
||||
public JsonDateTime toJson(ZonedDateTime input) {
|
||||
String date = input.toLocalDate().toString();
|
||||
String time = input.toLocalTime().toString();
|
||||
String timezone = input.getZone().toString();
|
||||
return new JsonDateTime(date, time, timezone);
|
||||
}
|
||||
@FromJson
|
||||
public ZonedDateTime fromJson(JsonDateTime input) {
|
||||
LocalDate date = LocalDate.parse(input.getDate());
|
||||
LocalTime time = LocalTime.parse(input.getTime());
|
||||
ZoneId timezone = ZoneId.of(input.getTimezone());
|
||||
return ZonedDateTime.of(date, time, timezone);
|
||||
}
|
||||
}
|
||||
public static class JsonDateTime {
|
||||
private String date;
|
||||
private String time;
|
||||
private String timezone;
|
||||
|
||||
public JsonDateTime() {
|
||||
}
|
||||
|
||||
public JsonDateTime(String date, String time, String timezone) {
|
||||
this.date = date;
|
||||
this.time = time;
|
||||
this.timezone = timezone;
|
||||
}
|
||||
|
||||
public String getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(String date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public String getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(String time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public String getTimezone() {
|
||||
return timezone;
|
||||
}
|
||||
|
||||
public void setTimezone(String timezone) {
|
||||
this.timezone = timezone;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package com.baeldung.moshi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.Moshi;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DefaultUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenDeserializing_thenFieldsGetDefaultValues() throws IOException {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.build();
|
||||
JsonAdapter<Post> jsonAdapter = moshi.adapter(Post.class);
|
||||
|
||||
String json = "{\"title\":\"My Post\"}";
|
||||
Post post = jsonAdapter.fromJson(json);
|
||||
System.out.println(post);
|
||||
}
|
||||
public static class Post {
|
||||
private String title;
|
||||
private String author;
|
||||
private String posted;
|
||||
|
||||
public Post() {
|
||||
posted = Instant.now().toString();
|
||||
}
|
||||
|
||||
public Post(String title, String author, String posted) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
this.posted = posted;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public String getPosted() {
|
||||
return posted;
|
||||
}
|
||||
|
||||
public void setPosted(String posted) {
|
||||
this.posted = posted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("title", title).append("author", author).append("posted", posted)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package com.baeldung.moshi;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.Moshi;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.junit.Test;
|
||||
|
||||
public class PrimitiveUnitTest {
|
||||
@Test
|
||||
public void whenSerializing_thenCorrectJsonProduced() {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.build();
|
||||
JsonAdapter<Post> jsonAdapter = moshi.adapter(Post.class);
|
||||
|
||||
Post post = new Post("My Post", "Baeldung", "This is my post");
|
||||
String json = jsonAdapter.toJson(post);
|
||||
System.out.println(json);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDeserializing_thenCorrectJsonConsumed() throws IOException {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.build();
|
||||
JsonAdapter<Post> jsonAdapter = moshi.adapter(Post.class);
|
||||
|
||||
String json = "{\"author\":\"Baeldung\",\"text\":\"This is my post\",\"title\":\"My Post\"}";
|
||||
Post post = jsonAdapter.fromJson(json);
|
||||
System.out.println(post);
|
||||
}
|
||||
|
||||
public static class Post {
|
||||
private String title;
|
||||
private String author;
|
||||
private String text;
|
||||
|
||||
public Post() {
|
||||
}
|
||||
|
||||
public Post(String title, String author, String text) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("title", title).append("author", author).append("text", text)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package com.baeldung.moshi;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.squareup.moshi.Json;
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.Moshi;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class RenameUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenSerializing_thenFieldsGetRenamed() {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.build();
|
||||
JsonAdapter<Post> jsonAdapter = moshi.adapter(Post.class);
|
||||
|
||||
Post post = new Post("My Post", "Baeldung");
|
||||
String json = jsonAdapter.toJson(post);
|
||||
System.out.println(json);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSerializing_thenRenamedFieldsGetConsumed() throws IOException {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.build();
|
||||
JsonAdapter<Post> jsonAdapter = moshi.adapter(Post.class);
|
||||
|
||||
String json = "{\"authored_by\":\"Baeldung\",\"title\":\"My Post\"}";
|
||||
Post post = jsonAdapter.fromJson(json);
|
||||
System.out.println(post);
|
||||
}
|
||||
public static class Post {
|
||||
private String title;
|
||||
@Json(name = "authored_by")
|
||||
private String author;
|
||||
|
||||
public Post() {
|
||||
}
|
||||
|
||||
public Post(String title, String author) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("title", title).append("author", author).toString();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
package com.baeldung.moshi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.squareup.moshi.FromJson;
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.Moshi;
|
||||
import com.squareup.moshi.ToJson;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SimpleAdapterUnitTest {
|
||||
@Test
|
||||
public void whenSerializing_thenAdapterUsed() {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.add(new AuthorAdapter())
|
||||
.build();
|
||||
JsonAdapter<Post> jsonAdapter = moshi.adapter(Post.class);
|
||||
|
||||
Post post = new Post("My Post", new Author("Baeldung", "baeldung@example.com"), "This is my post");
|
||||
String json = jsonAdapter.toJson(post);
|
||||
System.out.println(json);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDeserializing_thenAdapterUsed() throws IOException {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.add(new AuthorAdapter())
|
||||
.build();
|
||||
JsonAdapter<Post> jsonAdapter = moshi.adapter(Post.class);
|
||||
|
||||
String json = "{\"author\":\"Baeldung <baeldung@example.com>\",\"text\":\"This is my post\",\"title\":\"My Post\"}";
|
||||
Post post = jsonAdapter.fromJson(json);
|
||||
System.out.println(post);
|
||||
}
|
||||
public static class AuthorAdapter {
|
||||
private Pattern pattern = Pattern.compile("^(.*) <(.*)>$");
|
||||
@ToJson
|
||||
public String toJson(Author author) {
|
||||
return author.name + " <" + author.email + ">";
|
||||
}
|
||||
|
||||
@FromJson
|
||||
public Author fromJson(String author) {
|
||||
Matcher matcher = pattern.matcher(author);
|
||||
return matcher.find() ? new Author(matcher.group(1), matcher.group(2)) : null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Author {
|
||||
private String name;
|
||||
private String email;
|
||||
|
||||
public Author() {
|
||||
}
|
||||
|
||||
public Author(String name, String email) {
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("name", name).append("email", email).toString();
|
||||
}
|
||||
}
|
||||
public static class Post {
|
||||
private String title;
|
||||
private Author author;
|
||||
private String text;
|
||||
|
||||
public Post() {
|
||||
}
|
||||
|
||||
public Post(String title, Author author, String text) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public Author getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(Author author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("title", title).append("author", author).append("text", text)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.baeldung.moshi;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.Moshi;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class TransientUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenSerializing_thenTransientFieldIgnored() {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.build();
|
||||
JsonAdapter<Post> jsonAdapter = moshi.adapter(Post.class);
|
||||
|
||||
Post post = new Post("My Post", "Baeldung");
|
||||
String json = jsonAdapter.toJson(post);
|
||||
System.out.println(json);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDeserializing_thenTransientFieldIgnored() throws IOException {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.build();
|
||||
JsonAdapter<Post> jsonAdapter = moshi.adapter(Post.class);
|
||||
|
||||
String json = "{\"authored_by\":\"Baeldung\",\"title\":\"My Post\"}";
|
||||
Post post = jsonAdapter.fromJson(json);
|
||||
System.out.println(post);
|
||||
}
|
||||
public static class Post {
|
||||
private String title;
|
||||
private transient String author;
|
||||
|
||||
public Post() {
|
||||
}
|
||||
|
||||
public Post(String title, String author) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("title", title).append("author", author).toString();
|
||||
}
|
||||
}
|
||||
}
|
@ -18,6 +18,8 @@ public class App {
|
||||
final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(SpringConfig.class);
|
||||
context.register(SpringBatchConfig.class);
|
||||
context.register(SpringBatchRetryConfig.class);
|
||||
|
||||
context.refresh();
|
||||
|
||||
// Spring xml config
|
||||
@ -26,6 +28,8 @@ public class App {
|
||||
runJob(context, "firstBatchJob");
|
||||
runJob(context, "skippingBatchJob");
|
||||
runJob(context, "skipPolicyBatchJob");
|
||||
runJob(context, "retryBatchJob");
|
||||
|
||||
}
|
||||
|
||||
private static void runJob(AnnotationConfigApplicationContext context, String batchJobName) {
|
||||
|
@ -0,0 +1,117 @@
|
||||
package org.baeldung.batch;
|
||||
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.conn.ConnectTimeoutException;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.baeldung.batch.model.Transaction;
|
||||
import org.baeldung.batch.service.RecordFieldSetMapper;
|
||||
import org.baeldung.batch.service.RetryItemProcessor;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
|
||||
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
|
||||
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
|
||||
import org.springframework.batch.item.ItemProcessor;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemWriter;
|
||||
import org.springframework.batch.item.file.FlatFileItemReader;
|
||||
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
|
||||
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
|
||||
import org.springframework.batch.item.xml.StaxEventItemWriter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.dao.DeadlockLoserDataAccessException;
|
||||
import org.springframework.oxm.Marshaller;
|
||||
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
||||
@Configuration
|
||||
@EnableBatchProcessing
|
||||
public class SpringBatchRetryConfig {
|
||||
|
||||
private static final String[] tokens = { "username", "userid", "transactiondate", "amount" };
|
||||
private static final int TWO_SECONDS = 2000;
|
||||
|
||||
@Autowired
|
||||
private JobBuilderFactory jobBuilderFactory;
|
||||
|
||||
@Autowired
|
||||
private StepBuilderFactory stepBuilderFactory;
|
||||
|
||||
@Value("input/recordRetry.csv")
|
||||
private Resource inputCsv;
|
||||
|
||||
@Value("file:xml/retryOutput.xml")
|
||||
private Resource outputXml;
|
||||
|
||||
public ItemReader<Transaction> itemReader(Resource inputData) throws ParseException {
|
||||
DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
|
||||
tokenizer.setNames(tokens);
|
||||
DefaultLineMapper<Transaction> lineMapper = new DefaultLineMapper<>();
|
||||
lineMapper.setLineTokenizer(tokenizer);
|
||||
lineMapper.setFieldSetMapper(new RecordFieldSetMapper());
|
||||
FlatFileItemReader<Transaction> reader = new FlatFileItemReader<>();
|
||||
reader.setResource(inputData);
|
||||
reader.setLinesToSkip(1);
|
||||
reader.setLineMapper(lineMapper);
|
||||
return reader;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CloseableHttpClient closeableHttpClient() {
|
||||
final RequestConfig config = RequestConfig.custom()
|
||||
.setConnectTimeout(TWO_SECONDS)
|
||||
.build();
|
||||
return HttpClientBuilder.create().setDefaultRequestConfig(config).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ItemProcessor<Transaction, Transaction> retryItemProcessor() {
|
||||
return new RetryItemProcessor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ItemWriter<Transaction> itemWriter(Marshaller marshaller) {
|
||||
StaxEventItemWriter<Transaction> itemWriter = new StaxEventItemWriter<>();
|
||||
itemWriter.setMarshaller(marshaller);
|
||||
itemWriter.setRootTagName("transactionRecord");
|
||||
itemWriter.setResource(outputXml);
|
||||
return itemWriter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Marshaller marshaller() {
|
||||
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
|
||||
marshaller.setClassesToBeBound(Transaction.class);
|
||||
return marshaller;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Step retryStep(@Qualifier("retryItemProcessor") ItemProcessor<Transaction, Transaction> processor,
|
||||
ItemWriter<Transaction> writer) throws ParseException {
|
||||
return stepBuilderFactory.get("retryStep")
|
||||
.<Transaction, Transaction>chunk(10)
|
||||
.reader(itemReader(inputCsv))
|
||||
.processor(processor)
|
||||
.writer(writer)
|
||||
.faultTolerant()
|
||||
.retryLimit(3)
|
||||
.retry(ConnectTimeoutException.class)
|
||||
.retry(DeadlockLoserDataAccessException.class)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean(name = "retryBatchJob")
|
||||
public Job retryJob(@Qualifier("retryStep") Step retryStep) {
|
||||
return jobBuilderFactory
|
||||
.get("retryBatchJob")
|
||||
.start(retryStep)
|
||||
.build();
|
||||
}
|
||||
}
|
@ -9,6 +9,8 @@ import javax.xml.bind.annotation.XmlRootElement;
|
||||
public class Transaction {
|
||||
private String username;
|
||||
private int userId;
|
||||
private int age;
|
||||
private String postCode;
|
||||
private Date transactionDate;
|
||||
private double amount;
|
||||
|
||||
@ -46,9 +48,25 @@ public class Transaction {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public String getPostCode() {
|
||||
return postCode;
|
||||
}
|
||||
|
||||
public void setPostCode(String postCode) {
|
||||
this.postCode = postCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Transaction [username=" + username + ", userId=" + userId + ", transactionDate=" + transactionDate + ", amount=" + amount + "]";
|
||||
return "Transaction [username=" + username + ", userId=" + userId + ", age=" + age + ", postCode=" + postCode + ", transactionDate=" + transactionDate + ", amount=" + amount + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
package org.baeldung.batch.service;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.baeldung.batch.model.Transaction;
|
||||
import org.codehaus.jettison.json.JSONException;
|
||||
import org.codehaus.jettison.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.batch.item.ItemProcessor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class RetryItemProcessor implements ItemProcessor<Transaction, Transaction> {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RetryItemProcessor.class);
|
||||
|
||||
@Autowired
|
||||
private CloseableHttpClient closeableHttpClient;
|
||||
|
||||
@Override
|
||||
public Transaction process(Transaction transaction) throws IOException, JSONException {
|
||||
LOGGER.info("Attempting to process user with id={}", transaction.getUserId());
|
||||
HttpResponse response = fetchMoreUserDetails(transaction.getUserId());
|
||||
|
||||
//parse user's age and postCode from response and update transaction
|
||||
String result = EntityUtils.toString(response.getEntity());
|
||||
JSONObject userObject = new JSONObject(result);
|
||||
transaction.setAge(Integer.parseInt(userObject.getString("age")));
|
||||
transaction.setPostCode(userObject.getString("postCode"));
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
private HttpResponse fetchMoreUserDetails(int id) throws IOException {
|
||||
final HttpGet request = new HttpGet("http://www.baeldung.com:81/user/" + id);
|
||||
return closeableHttpClient.execute(request);
|
||||
}
|
||||
}
|
3
spring-batch/src/main/resources/input/recordRetry.csv
Normal file
3
spring-batch/src/main/resources/input/recordRetry.csv
Normal file
@ -0,0 +1,3 @@
|
||||
username, user_id, transaction_date, transaction_amount
|
||||
sammy, 1234, 31/10/2015, 10000
|
||||
john, 9999, 3/12/2015, 12321
|
|
@ -54,4 +54,19 @@
|
||||
</batch:tasklet>
|
||||
</batch:step>
|
||||
</batch:job>
|
||||
|
||||
<batch:job id="retryBatchJob">
|
||||
<batch:step id="retryStep">
|
||||
<batch:tasklet>
|
||||
<batch:chunk reader="itemReader" writer="itemWriter"
|
||||
processor="retryItemProcessor" commit-interval="10"
|
||||
retry-limit="3">
|
||||
<batch:retryable-exception-classes>
|
||||
<batch:include class="org.apache.http.conn.ConnectTimeoutException"/>
|
||||
<batch:include class="org.springframework.dao.DeadlockLoserDataAccessException"/>
|
||||
</batch:retryable-exception-classes>
|
||||
</batch:chunk>
|
||||
</batch:tasklet>
|
||||
</batch:step>
|
||||
</batch:job>
|
||||
</beans>
|
||||
|
@ -0,0 +1,90 @@
|
||||
package org.baeldung.batch;
|
||||
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.conn.ConnectTimeoutException;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobInstance;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.JobParametersBuilder;
|
||||
import org.springframework.batch.test.AssertFile;
|
||||
import org.springframework.batch.test.JobLauncherTestUtils;
|
||||
import org.springframework.batch.test.context.SpringBatchTest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBatchTest
|
||||
@EnableAutoConfiguration
|
||||
@ContextConfiguration(classes = { SpringBatchRetryConfig.class })
|
||||
public class SpringBatchRetryIntegrationTest {
|
||||
|
||||
private static final String TEST_OUTPUT = "xml/retryOutput.xml";
|
||||
private static final String EXPECTED_OUTPUT = "src/test/resources/output/batchRetry/retryOutput.xml";
|
||||
|
||||
@Autowired
|
||||
private JobLauncherTestUtils jobLauncherTestUtils;
|
||||
|
||||
@MockBean
|
||||
private CloseableHttpClient closeableHttpClient;
|
||||
|
||||
@Mock
|
||||
private CloseableHttpResponse httpResponse;
|
||||
|
||||
@Test
|
||||
public void whenEndpointAlwaysFail_thenJobFails() throws Exception {
|
||||
when(closeableHttpClient.execute(any()))
|
||||
.thenThrow(new ConnectTimeoutException("Endpoint is down"));
|
||||
|
||||
JobExecution jobExecution = jobLauncherTestUtils.launchJob(defaultJobParameters());
|
||||
JobInstance actualJobInstance = jobExecution.getJobInstance();
|
||||
ExitStatus actualJobExitStatus = jobExecution.getExitStatus();
|
||||
|
||||
assertThat(actualJobInstance.getJobName(), is("retryBatchJob"));
|
||||
assertThat(actualJobExitStatus.getExitCode(), is("FAILED"));
|
||||
assertThat(actualJobExitStatus.getExitDescription(), containsString("org.apache.http.conn.ConnectTimeoutException"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenEndpointFailsTwicePasses3rdTime_thenSuccess() throws Exception {
|
||||
FileSystemResource expectedResult = new FileSystemResource(EXPECTED_OUTPUT);
|
||||
FileSystemResource actualResult = new FileSystemResource(TEST_OUTPUT);
|
||||
|
||||
//fails for first two calls and passes third time onwards
|
||||
when(httpResponse.getEntity())
|
||||
.thenReturn(new StringEntity("{ \"age\":10, \"postCode\":\"430222\" }"));
|
||||
when(closeableHttpClient.execute(any()))
|
||||
.thenThrow(new ConnectTimeoutException("Timeout count 1"))
|
||||
.thenThrow(new ConnectTimeoutException("Timeout count 2"))
|
||||
.thenReturn(httpResponse);
|
||||
|
||||
JobExecution jobExecution = jobLauncherTestUtils.launchJob(defaultJobParameters());
|
||||
JobInstance actualJobInstance = jobExecution.getJobInstance();
|
||||
ExitStatus actualJobExitStatus = jobExecution.getExitStatus();
|
||||
|
||||
assertThat(actualJobInstance.getJobName(), is("retryBatchJob"));
|
||||
assertThat(actualJobExitStatus.getExitCode(), is("COMPLETED"));
|
||||
AssertFile.assertFileEquals(expectedResult, actualResult);
|
||||
}
|
||||
|
||||
private JobParameters defaultJobParameters() {
|
||||
JobParametersBuilder paramsBuilder = new JobParametersBuilder();
|
||||
paramsBuilder.addString("jobID", String.valueOf(System.currentTimeMillis()));
|
||||
return paramsBuilder.toJobParameters();
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><transactionRecord><transactionRecord><age>10</age><amount>10000.0</amount><postCode>430222</postCode><transactionDate>2015-10-31T00:00:00+05:30</transactionDate><userId>1234</userId><username>sammy</username></transactionRecord><transactionRecord><age>10</age><amount>12321.0</amount><postCode>430222</postCode><transactionDate>2015-12-03T00:00:00+05:30</transactionDate><userId>9999</userId><username>john</username></transactionRecord></transactionRecord>
|
1
spring-batch/xml/retryOutput.xml
Normal file
1
spring-batch/xml/retryOutput.xml
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><transactionRecord><transactionRecord><age>10</age><amount>10000.0</amount><postCode>430222</postCode><transactionDate>2015-10-31T00:00:00+05:30</transactionDate><userId>1234</userId><username>sammy</username></transactionRecord><transactionRecord><age>10</age><amount>12321.0</amount><postCode>430222</postCode><transactionDate>2015-12-03T00:00:00+05:30</transactionDate><userId>9999</userId><username>john</username></transactionRecord></transactionRecord>
|
@ -41,12 +41,18 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.java-json-tools</groupId>
|
||||
<artifactId>json-patch</artifactId>
|
||||
<version>${jsonpatch.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
<properties>
|
||||
<xstream.version>1.4.9</xstream.version>
|
||||
<jsonpatch.version>1.12</jsonpatch.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
@ -0,0 +1,12 @@
|
||||
package com.baeldung;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class CustomerSpringBootRestApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(CustomerSpringBootRestApplication.class, args);
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package com.baeldung.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Customer {
|
||||
private String id;
|
||||
private String telephone;
|
||||
private List<String> favorites;
|
||||
private Map<String, Boolean> communicationPreferences;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(String id, String telephone, List<String> favorites, Map<String, Boolean> communicationPreferences) {
|
||||
this(telephone, favorites, communicationPreferences);
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Customer(String telephone, List<String> favorites, Map<String, Boolean> communicationPreferences) {
|
||||
this.telephone = telephone;
|
||||
this.favorites = favorites;
|
||||
this.communicationPreferences = communicationPreferences;
|
||||
}
|
||||
|
||||
public static Customer fromCustomer(Customer customer) {
|
||||
return new Customer(customer.getId(), customer.getTelephone(), customer.getFavorites(), customer.getCommunicationPreferences());
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTelephone() {
|
||||
return telephone;
|
||||
}
|
||||
|
||||
public void setTelephone(String telephone) {
|
||||
this.telephone = telephone;
|
||||
}
|
||||
|
||||
public Map<String, Boolean> getCommunicationPreferences() {
|
||||
return communicationPreferences;
|
||||
}
|
||||
|
||||
public void setCommunicationPreferences(Map<String, Boolean> communicationPreferences) {
|
||||
this.communicationPreferences = communicationPreferences;
|
||||
}
|
||||
|
||||
public List<String> getFavorites() {
|
||||
return favorites;
|
||||
}
|
||||
|
||||
public void setFavorites(List<String> favorites) {
|
||||
this.favorites = favorites;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof Customer)) {
|
||||
return false;
|
||||
}
|
||||
Customer customer = (Customer) o;
|
||||
return Objects.equals(id, customer.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package com.baeldung.service;
|
||||
|
||||
public interface CustomerIdGenerator {
|
||||
int generateNextId();
|
||||
}
|
||||
|
@ -0,0 +1,14 @@
|
||||
package com.baeldung.service;
|
||||
|
||||
import com.baeldung.model.Customer;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface CustomerService {
|
||||
|
||||
Customer createCustomer(Customer customer);
|
||||
|
||||
Optional<Customer> findCustomer(String id);
|
||||
|
||||
void updateCustomer(Customer customer);
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.baeldung.service.impl;
|
||||
|
||||
import com.baeldung.service.CustomerIdGenerator;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Component
|
||||
public class CustomerIdGeneratorImpl implements CustomerIdGenerator {
|
||||
private static final AtomicInteger SEQUENCE = new AtomicInteger();
|
||||
|
||||
@Override
|
||||
public int generateNextId() {
|
||||
return SEQUENCE.incrementAndGet();
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.baeldung.service.impl;
|
||||
|
||||
import com.baeldung.model.Customer;
|
||||
import com.baeldung.service.CustomerIdGenerator;
|
||||
import com.baeldung.service.CustomerService;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class CustomerServiceImpl implements CustomerService {
|
||||
private CustomerIdGenerator customerIdGenerator;
|
||||
private List<Customer> customers = new ArrayList<>();
|
||||
|
||||
@Autowired
|
||||
public CustomerServiceImpl(CustomerIdGenerator customerIdGenerator) {
|
||||
this.customerIdGenerator = customerIdGenerator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Customer createCustomer(Customer customer) {
|
||||
customer.setId(Integer.toString(customerIdGenerator.generateNextId()));
|
||||
customers.add(customer);
|
||||
return customer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Customer> findCustomer(String id) {
|
||||
return customers.stream()
|
||||
.filter(customer -> customer.getId().equals(id))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCustomer(Customer customer) {
|
||||
customers.set(customers.indexOf(customer), customer);
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package com.baeldung.web.controller;
|
||||
|
||||
import com.baeldung.model.Customer;
|
||||
import com.baeldung.service.CustomerService;
|
||||
import com.baeldung.web.exception.CustomerNotFoundException;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.github.fge.jsonpatch.JsonPatch;
|
||||
import com.github.fge.jsonpatch.JsonPatchException;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = "/customers")
|
||||
public class CustomerRestController {
|
||||
private CustomerService customerService;
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@Autowired
|
||||
public CustomerRestController(CustomerService customerService) {
|
||||
this.customerService = customerService;
|
||||
}
|
||||
|
||||
@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
public ResponseEntity<Customer> createCustomer(@RequestBody Customer customer) {
|
||||
Customer customerCreated = customerService.createCustomer(customer);
|
||||
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
|
||||
.path("/{id}")
|
||||
.buildAndExpand(customerCreated.getId())
|
||||
.toUri();
|
||||
return ResponseEntity.created(location).build();
|
||||
}
|
||||
|
||||
@PatchMapping(path = "/{id}", consumes = "application/json-patch+json")
|
||||
public ResponseEntity<Customer> updateCustomer(@PathVariable String id,
|
||||
@RequestBody JsonPatch patch) {
|
||||
try {
|
||||
Customer customer = customerService.findCustomer(id).orElseThrow(CustomerNotFoundException::new);
|
||||
Customer customerPatched = applyPatchToCustomer(patch, customer);
|
||||
customerService.updateCustomer(customerPatched);
|
||||
|
||||
return ResponseEntity.ok(customerPatched);
|
||||
} catch (CustomerNotFoundException e) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
|
||||
} catch (JsonPatchException | JsonProcessingException e) {
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
||||
}
|
||||
}
|
||||
|
||||
private Customer applyPatchToCustomer(JsonPatch patch, Customer targetCustomer) throws JsonPatchException, JsonProcessingException {
|
||||
JsonNode patched = patch.apply(objectMapper.convertValue(targetCustomer, JsonNode.class));
|
||||
return objectMapper.treeToValue(patched, Customer.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package com.baeldung.web.exception;
|
||||
|
||||
public class CustomerNotFoundException extends RuntimeException {
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.baeldung.service.impl;
|
||||
|
||||
import com.baeldung.service.CustomerIdGenerator;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class CustomerIdGeneratorImplUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenIdGeneratedPreviously_whenGenerated_thenIdIsIncremented(){
|
||||
CustomerIdGenerator customerIdGenerator = new CustomerIdGeneratorImpl();
|
||||
int firstId = customerIdGenerator.generateNextId();
|
||||
assertThat(customerIdGenerator.generateNextId()).isEqualTo(++firstId);
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package com.baeldung.service.impl;
|
||||
|
||||
|
||||
import com.baeldung.model.Customer;
|
||||
import com.baeldung.service.CustomerIdGenerator;
|
||||
import com.baeldung.service.CustomerService;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
import static com.baeldung.model.Customer.fromCustomer;
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Optional.empty;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CustomerServiceImplUnitTest {
|
||||
|
||||
@Mock
|
||||
private CustomerIdGenerator mockCustomerIdGenerator;
|
||||
|
||||
private CustomerService customerService;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
customerService = new CustomerServiceImpl(mockCustomerIdGenerator);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCustomerIsCreated_thenNewCustomerDetailsAreCorrect() {
|
||||
Map<String, Boolean> communicationPreferences = new HashMap<>();
|
||||
communicationPreferences.put("post", true);
|
||||
communicationPreferences.put("email", true);
|
||||
Customer customer = new Customer("001-555-1234", asList("Milk", "Eggs"), communicationPreferences);
|
||||
given(mockCustomerIdGenerator.generateNextId()).willReturn(1);
|
||||
|
||||
Customer newCustomer = customerService.createCustomer(customer);
|
||||
|
||||
assertThat(newCustomer.getId()).isEqualTo("1");
|
||||
assertThat(newCustomer.getTelephone()).isEqualTo("001-555-1234");
|
||||
assertThat(newCustomer.getFavorites()).containsExactly("Milk", "Eggs");
|
||||
assertThat(newCustomer.getCommunicationPreferences()).isEqualTo(communicationPreferences);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNonExistentCustomer_whenCustomerIsLookedUp_thenCustomerCanNotBeFound() {
|
||||
assertThat(customerService.findCustomer("CUST12345")).isEqualTo(empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCustomerIsCreated_thenCustomerCanBeFound() {
|
||||
Map<String, Boolean> communicationPreferences = new HashMap<>();
|
||||
communicationPreferences.put("post", true);
|
||||
communicationPreferences.put("email", true);
|
||||
Customer customer = new Customer("001-555-1234", asList("Milk", "Eggs"), communicationPreferences);
|
||||
given(mockCustomerIdGenerator.generateNextId()).willReturn(7890);
|
||||
|
||||
customerService.createCustomer(customer);
|
||||
Customer lookedUpCustomer = customerService.findCustomer("7890").get();
|
||||
|
||||
assertThat(lookedUpCustomer.getId()).isEqualTo("7890");
|
||||
assertThat(lookedUpCustomer.getTelephone()).isEqualTo("001-555-1234");
|
||||
assertThat(lookedUpCustomer.getFavorites()).containsExactly("Milk", "Eggs");
|
||||
assertThat(lookedUpCustomer.getCommunicationPreferences()).isEqualTo(communicationPreferences);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCustomerUpdated_thenDetailsUpdatedCorrectly() {
|
||||
given(mockCustomerIdGenerator.generateNextId()).willReturn(7890);
|
||||
Map<String, Boolean> communicationPreferences = new HashMap<>();
|
||||
communicationPreferences.put("post", true);
|
||||
communicationPreferences.put("email", true);
|
||||
Customer customer = new Customer("001-555-1234", asList("Milk", "Eggs"), communicationPreferences);
|
||||
Customer newCustomer = customerService.createCustomer(customer);
|
||||
|
||||
Customer customerWithUpdates = fromCustomer(newCustomer);
|
||||
customerWithUpdates.setTelephone("001-555-6789");
|
||||
customerService.updateCustomer(customerWithUpdates);
|
||||
Customer lookedUpCustomer = customerService.findCustomer("7890").get();
|
||||
|
||||
assertThat(lookedUpCustomer.getId()).isEqualTo("7890");
|
||||
assertThat(lookedUpCustomer.getTelephone()).isEqualTo("001-555-6789");
|
||||
assertThat(lookedUpCustomer.getFavorites()).containsExactly("Milk", "Eggs");
|
||||
assertThat(lookedUpCustomer.getCommunicationPreferences()).isEqualTo(communicationPreferences);
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package com.baeldung.web.controller;
|
||||
|
||||
import com.baeldung.model.Customer;
|
||||
import com.baeldung.service.CustomerService;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
public class CustomerRestControllerIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private CustomerService customerService;
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate testRestTemplate;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
testRestTemplate.getRestTemplate().setRequestFactory(new HttpComponentsClientHttpRequestFactory());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenExistingCustomer_whenPatched_thenOnlyPatchedFieldsUpdated() {
|
||||
Map<String, Boolean> communicationPreferences = new HashMap<>();
|
||||
communicationPreferences.put("post", true);
|
||||
communicationPreferences.put("email", true);
|
||||
Customer newCustomer = new Customer("001-555-1234", Arrays.asList("Milk", "Eggs"),
|
||||
communicationPreferences);
|
||||
Customer customer = customerService.createCustomer(newCustomer);
|
||||
|
||||
|
||||
String patchBody = "[ { \"op\": \"replace\", \"path\": \"/telephone\", \"value\": \"001-555-5678\" },\n"
|
||||
+ "{\"op\": \"add\", \"path\": \"/favorites/0\", \"value\": \"Bread\" }]";
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.valueOf("application/json-patch+json"));
|
||||
ResponseEntity<Customer> patchResponse
|
||||
= testRestTemplate.exchange("/customers/{id}",
|
||||
HttpMethod.PATCH,
|
||||
new HttpEntity<>(patchBody, headers),
|
||||
Customer.class,
|
||||
customer.getId());
|
||||
|
||||
Customer customerPatched = patchResponse.getBody();
|
||||
assertThat(patchResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(customerPatched.getId()).isEqualTo(customer.getId());
|
||||
assertThat(customerPatched.getTelephone()).isEqualTo("001-555-5678");
|
||||
assertThat(customerPatched.getCommunicationPreferences().get("post")).isTrue();
|
||||
assertThat(customerPatched.getCommunicationPreferences().get("email")).isTrue();
|
||||
assertThat(customerPatched.getFavorites()).containsExactly("Bread", "Milk", "Eggs");
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
package com.baeldung.web.controller;
|
||||
|
||||
import com.baeldung.model.Customer;
|
||||
import com.baeldung.service.CustomerService;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Optional.empty;
|
||||
import static java.util.Optional.of;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern;
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@AutoConfigureMockMvc
|
||||
public class CustomerRestControllerUnitTest {
|
||||
|
||||
private static final String APPLICATION_JSON_PATCH_JSON = "application/json-patch+json";
|
||||
|
||||
@Autowired
|
||||
private MockMvc mvc;
|
||||
|
||||
@MockBean
|
||||
private CustomerService mockCustomerService;
|
||||
|
||||
@Autowired
|
||||
ApplicationContext context;
|
||||
|
||||
@Test
|
||||
public void whenCustomerCreated_then201ReturnedWithNewCustomerLocation() throws Exception {
|
||||
Map<String, Boolean> communicationPreferences = new HashMap<>();
|
||||
communicationPreferences.put("post", true);
|
||||
communicationPreferences.put("email", true);
|
||||
Customer customer = new Customer("001-555-1234", asList("Milk", "Eggs"), communicationPreferences);
|
||||
|
||||
Customer persistedCustomer = Customer.fromCustomer(customer);
|
||||
persistedCustomer.setId("1");
|
||||
|
||||
given(mockCustomerService.createCustomer(customer)).willReturn(persistedCustomer);
|
||||
|
||||
String createCustomerRequestBody = "{"
|
||||
+ "\"telephone\": \"001-555-1234\",\n"
|
||||
+ "\"favorites\": [\"Milk\", \"Eggs\"],\n"
|
||||
+ "\"communicationPreferences\": {\"post\":true, \"email\":true}\n"
|
||||
+ "}";
|
||||
mvc.perform(post("/customers")
|
||||
.contentType(APPLICATION_JSON)
|
||||
.content(createCustomerRequestBody))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(redirectedUrlPattern("http://*/customers/1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNonExistentCustomer_whenPatched_then404Returned() throws Exception {
|
||||
given(mockCustomerService.findCustomer("1")).willReturn(empty());
|
||||
|
||||
String patchInstructions = "[{\"op\":\"replace\",\"path\": \"/telephone\",\"value\":\"001-555-5678\"}]";
|
||||
mvc.perform(patch("/customers/1")
|
||||
.contentType(APPLICATION_JSON_PATCH_JSON)
|
||||
.content(patchInstructions))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenExistingCustomer_whenPatched_thenReturnPatchedCustomer() throws Exception {
|
||||
Map<String, Boolean> communicationPreferences = new HashMap<>();
|
||||
communicationPreferences.put("post", true);
|
||||
communicationPreferences.put("email", true);
|
||||
Customer customer = new Customer("1", "001-555-1234", asList("Milk", "Eggs"), communicationPreferences);
|
||||
|
||||
given(mockCustomerService.findCustomer("1")).willReturn(of(customer));
|
||||
|
||||
String patchInstructions = "[{\"op\":\"replace\",\"path\": \"/telephone\",\"value\":\"001-555-5678\"}]";
|
||||
mvc.perform(patch("/customers/1")
|
||||
.contentType(APPLICATION_JSON_PATCH_JSON)
|
||||
.content(patchInstructions))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.id", is("1")))
|
||||
.andExpect(jsonPath("$.telephone", is("001-555-5678")))
|
||||
.andExpect(jsonPath("$.favorites", is(asList("Milk", "Eggs"))))
|
||||
.andExpect(jsonPath("$.communicationPreferences", is(communicationPreferences)));
|
||||
}
|
||||
}
|
@ -21,7 +21,8 @@
|
||||
<module>spring-security-cors</module>
|
||||
<module>spring-security-kerberos</module>
|
||||
<module>spring-security-mvc</module>
|
||||
<module>spring-security-mvc-boot</module>
|
||||
<module>spring-security-mvc-boot-1</module>
|
||||
<module>spring-security-mvc-boot-2</module>
|
||||
<module>spring-security-mvc-custom</module>
|
||||
<module>spring-security-mvc-digest-auth</module>
|
||||
<module>spring-security-mvc-jsonview</module>
|
||||
|
@ -1,4 +1,4 @@
|
||||
## Spring Boot Security MVC
|
||||
## Spring Boot Security MVC - 1
|
||||
|
||||
This module contains articles about Spring Security with Spring MVC in Boot applications
|
||||
|
||||
@ -9,13 +9,9 @@ The "REST With Spring" Classes: http://github.learnspringsecurity.com
|
||||
- [A Custom Security Expression with Spring Security](https://www.baeldung.com/spring-security-create-new-custom-security-expression)
|
||||
- [Custom AccessDecisionVoters in Spring Security](https://www.baeldung.com/spring-security-custom-voter)
|
||||
- [Spring Security: Authentication with a Database-backed UserDetailsService](https://www.baeldung.com/spring-security-authentication-with-a-database)
|
||||
- [Two Login Pages with Spring Security](https://www.baeldung.com/spring-security-two-login-pages)
|
||||
- [Multiple Entry Points in Spring Security](https://www.baeldung.com/spring-security-multiple-entry-points)
|
||||
- [Multiple Authentication Providers in Spring Security](https://www.baeldung.com/spring-security-multiple-auth-providers)
|
||||
- [Granted Authority Versus Role in Spring Security](https://www.baeldung.com/spring-security-granted-authority-vs-role)
|
||||
- [Spring Data with Spring Security](https://www.baeldung.com/spring-data-security)
|
||||
- [Granted Authority Versus Role in Spring Security](https://www.baeldung.com/spring-security-granted-authority-vs-role)
|
||||
- [Spring Security – Whitelist IP Range](https://www.baeldung.com/spring-security-whitelist-ip-range)
|
||||
- [Find the Registered Spring Security Filters](https://www.baeldung.com/spring-security-registered-filters)
|
||||
- [HTTPS using Self-Signed Certificate in Spring Boot](https://www.baeldung.com/spring-boot-https-self-signed-certificate)
|
||||
- [Spring Security: Exploring JDBC Authentication](https://www.baeldung.com/spring-security-jdbc-authentication)
|
||||
- More articles: [[next -->]](/../spring-security-mvc-boot-2)
|
||||
|
240
spring-security-modules/spring-security-mvc-boot-1/pom.xml
Normal file
240
spring-security-modules/spring-security-mvc-boot-1/pom.xml
Normal file
@ -0,0 +1,240 @@
|
||||
<?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>
|
||||
<artifactId>spring-security-mvc-boot-1</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>spring-security-mvc-boot-1</name>
|
||||
<packaging>war</packaging>
|
||||
<description>Spring Security MVC Boot - 1</description>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../parent-boot-2</relativePath>
|
||||
</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>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.thymeleaf.extras</groupId>
|
||||
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-data</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-library</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>taglibs</groupId>
|
||||
<artifactId>standard</artifactId>
|
||||
<version>${taglibs-standard.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-taglibs</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet.jsp.jstl</groupId>
|
||||
<artifactId>jstl-api</artifactId>
|
||||
<version>${jstl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache-core</artifactId>
|
||||
<version>${ehcache-core.version}</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.cargo</groupId>
|
||||
<artifactId>cargo-maven2-plugin</artifactId>
|
||||
<version>${cargo-maven2-plugin.version}</version>
|
||||
<configuration>
|
||||
<wait>true</wait>
|
||||
<container>
|
||||
<containerId>tomcat8x</containerId>
|
||||
<type>embedded</type>
|
||||
<systemProperties>
|
||||
<!-- <provPersistenceTarget>cargo</provPersistenceTarget> -->
|
||||
</systemProperties>
|
||||
</container>
|
||||
<configuration>
|
||||
<properties>
|
||||
<cargo.servlet.port>8082</cargo.servlet.port>
|
||||
</properties>
|
||||
</configuration>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>live</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.cargo</groupId>
|
||||
<artifactId>cargo-maven2-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>start-server</id>
|
||||
<phase>pre-integration-test</phase>
|
||||
<goals>
|
||||
<goal>start</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>stop-server</id>
|
||||
<phase>post-integration-test</phase>
|
||||
<goals>
|
||||
<goal>stop</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>integration-test</phase>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>none</exclude>
|
||||
</excludes>
|
||||
<includes>
|
||||
<include>**/*LiveTest.java</include>
|
||||
</includes>
|
||||
<systemPropertyVariables>
|
||||
<webTarget>cargo</webTarget>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>entryPoints</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>integration-test</phase>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/*LiveTest.java</exclude>
|
||||
<exclude>**/*IntegrationTest.java</exclude>
|
||||
<exclude>**/*IntTest.java</exclude>
|
||||
</excludes>
|
||||
<includes>
|
||||
<include>**/*EntryPointsTest.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<test.mime>json</test.mime>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<properties>
|
||||
<start-class>org.baeldung.custom.Application</start-class>
|
||||
<!--If you want to run the example with the voters comment the tag
|
||||
above and uncomment the one below -->
|
||||
<!--<start-class>org.baeldung.voter.VoterApplication</start-class> -->
|
||||
|
||||
<taglibs-standard.version>1.1.2</taglibs-standard.version>
|
||||
<cargo-maven2-plugin.version>1.6.1</cargo-maven2-plugin.version>
|
||||
<ehcache-core.version>2.6.11</ehcache-core.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -13,7 +13,6 @@ import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.baeldung.models.AppUser;
|
||||
import com.baeldung.models.Tweet;
|
||||
|
||||
public interface UserRepository extends CrudRepository<AppUser, Long> {
|
||||
AppUser findByUsername(String username);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user