From b0b3a20749525083669e6219c7a5534a4576898b Mon Sep 17 00:00:00 2001 From: Sameera Nelson Date: Wed, 4 May 2016 22:55:34 +0530 Subject: [PATCH 001/269] Adding neo4j project skeleton --- spring-data-neo4j/README.md | 15 ++++ spring-data-neo4j/pom.xml | 69 ++++++++++++++++++ .../src/main/resources/logback.xml | 20 +++++ spring-data-neo4j/src/main/resources/test.png | Bin 0 -> 855 bytes 4 files changed, 104 insertions(+) create mode 100644 spring-data-neo4j/README.md create mode 100644 spring-data-neo4j/pom.xml create mode 100644 spring-data-neo4j/src/main/resources/logback.xml create mode 100644 spring-data-neo4j/src/main/resources/test.png diff --git a/spring-data-neo4j/README.md b/spring-data-neo4j/README.md new file mode 100644 index 0000000000..89eae99f05 --- /dev/null +++ b/spring-data-neo4j/README.md @@ -0,0 +1,15 @@ +## Spring Data Redis + +### Relevant Articles: +- [Introduction to Spring Data Redis](http://www.baeldung.com/spring-data-redis-tutorial) + +### Build the Project with Tests Running +``` +mvn clean install +``` + +### Run Tests Directly +``` +mvn test +``` + diff --git a/spring-data-neo4j/pom.xml b/spring-data-neo4j/pom.xml new file mode 100644 index 0000000000..5d04e0c3b4 --- /dev/null +++ b/spring-data-neo4j/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + com.baeldung + spring-data-neo4j + 1.0 + jar + + + UTF-8 + 4.2.5.RELEASE + 4.1.1.RELEASE + 0.8.0 + + + + + org.springframework.data + spring-data-neo4j + ${spring-data-neo4j} + + + + cglib + cglib-nodep + 2.2 + + + + log4j + log4j + 1.2.16 + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + junit + junit + 4.12 + test + + + + org.springframework + spring-test + ${spring.version} + test + + + + com.lordofthejars + nosqlunit-redis + ${nosqlunit.version} + + + + diff --git a/spring-data-neo4j/src/main/resources/logback.xml b/spring-data-neo4j/src/main/resources/logback.xml new file mode 100644 index 0000000000..215eeede64 --- /dev/null +++ b/spring-data-neo4j/src/main/resources/logback.xml @@ -0,0 +1,20 @@ + + + + + web - %date [%thread] %-5level %logger{36} - %message%n + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-data-neo4j/src/main/resources/test.png b/spring-data-neo4j/src/main/resources/test.png new file mode 100644 index 0000000000000000000000000000000000000000..c3b5e8027635ff4f0a0b10c0a9a6aa7a014e6086 GIT binary patch literal 855 zcmex=6kE^cmKJ|O{KK0!WiZUHd? zL17V5QBfX#aS1UI2_X?t5k_Vf7B*H^PBu0!em)*P5fKr7L0%pn0bT(feo-D?UVdI4 zpg0dNAHM*Q$HT+J$HNcg@q#%Zh5rvQ2y!sUFvu`73NkPWGBOJ?{y)MX0rV0OKpYGv zIoQ})S%5M+0t`%y%uFn-%&bsZMkb)c1=$oC*g1rh3>^~-jRG5mMVuBM1ge%|WME=O zF^8Fjk%^U!0Vt;gv=3+$3p2tNMkYaKCBqLwfr*X6ijMzpG4L=04G?4&WUyx___R78 z`bEZ3n*%y$c1p?=OzsY{vOIcDRID^@mH5k5n_VmCLN*tlQtc~BqmaI3acZm^A1dHBrChNRU-KfIG`3a9F1Z+JCT zaBkFRt*1+W!zihZ}s%F&cxn?h~EIRD%9;ni-#KyOjOZ3l7 z_6Ks(XSKVYPbdvPm!tpIJj%Ot(S2`WC0AaXj1Ds{Yc~e@JYj`ND^=I^G)#%-Q1qX7 z;Q8}@p=SNS>z3K2PrXivv`$ Date: Mon, 9 May 2016 00:29:00 +0530 Subject: [PATCH 002/269] Adding example project --- .../spring/data/neo4j/BookServiceTest.java | 40 ++++++++++++ .../config/LibraryNeo4jConfiguration.java | 32 ++++++++++ .../spring/data/neo4j/model/Book.java | 54 ++++++++++++++++ .../data/neo4j/repostory/BookRepository.java | 22 +++++++ .../data/neo4j/service/BookService.java | 62 +++++++++++++++++++ 5 files changed, 210 insertions(+) create mode 100644 spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/BookServiceTest.java create mode 100644 spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/LibraryNeo4jConfiguration.java create mode 100644 spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/model/Book.java create mode 100644 spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/BookRepository.java create mode 100644 spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookService.java diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/BookServiceTest.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/BookServiceTest.java new file mode 100644 index 0000000000..100465838e --- /dev/null +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/BookServiceTest.java @@ -0,0 +1,40 @@ +package com.baeldung.spring.data.neo4j; + +import com.baeldung.spring.data.neo4j.config.LibraryNeo4jConfiguration; +import com.baeldung.spring.data.neo4j.model.Book; +import com.baeldung.spring.data.neo4j.model.Person; +import com.baeldung.spring.data.neo4j.service.BookService; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import static org.junit.Assert.assertEquals; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = LibraryNeo4jConfiguration.class) +public class BookServiceTest { + + private static final Log LOGGER = LogFactory.getLog(BookServiceTest.class); + + @Autowired + private BookService bookService; + + @Test + public void testSaveBook() { + final Person author1 = new Person(); + author1.setName("Mark Twain"); + author1.setBorn(1835); + final Book book = new Book(); + book.setTitle("The Adventures of Tom Sawyer"); + book.setReleased(1876); + book.setPerson(author1); + + bookService.save(book); + final Book savedBook = bookService.findBookById(book.getId()); + assertEquals(book.getTitle(), savedBook.getTitle()); + } +} diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/LibraryNeo4jConfiguration.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/LibraryNeo4jConfiguration.java new file mode 100644 index 0000000000..c497c944d1 --- /dev/null +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/LibraryNeo4jConfiguration.java @@ -0,0 +1,32 @@ +package com.baeldung.spring.data.neo4j.config; + + +import org.neo4j.ogm.session.SessionFactory; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.neo4j.config.Neo4jConfiguration; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.server.Neo4jServer; +import org.springframework.data.neo4j.server.RemoteServer; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.transaction.annotation.EnableTransactionManagement; + + +@Configuration +@ComponentScan("com.baeldung.spring.data.neo4j") +@EnableNeo4jRepositories(basePackages = "com.baeldung.spring.data.neo4j.repostory") +public class LibraryNeo4jConfiguration extends Neo4jConfiguration { + + public static final String URL = System.getenv("NEO4J_URL") != null ? System.getenv("NEO4J_URL") : "http://localhost:7474"; + + @Override + public Neo4jServer neo4jServer() { + return new RemoteServer(URL,"neo4j","password"); + } + + @Override + public SessionFactory getSessionFactory() { + return new SessionFactory("com.baeldung.spring.data.neo4j.model"); + } +} \ No newline at end of file diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/model/Book.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/model/Book.java new file mode 100644 index 0000000000..2c643a4b7c --- /dev/null +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/model/Book.java @@ -0,0 +1,54 @@ +package com.baeldung.spring.data.neo4j.model; + +import org.neo4j.graphdb.Direction; +import org.neo4j.ogm.annotation.*; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +@NodeEntity +public class Book { + + private static final AtomicLong TS = new AtomicLong(); + + @GraphId + private Long id; + private String title; + private int released; + + @Relationship(type="AUTHORED_BY", direction = Relationship.INCOMING) + private Person person; + + public Book() { + this.id = TS.getAndIncrement(); + } + + public Long getId() { + return id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public int getReleased() { + return released; + } + + public void setReleased(int released) { + this.released = released; + } + + public Person getPerson() { + return person; + } + + public void setPerson(Person person) { + this.person = person; + } +} \ No newline at end of file diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/BookRepository.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/BookRepository.java new file mode 100644 index 0000000000..5c980b0381 --- /dev/null +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/BookRepository.java @@ -0,0 +1,22 @@ +package com.baeldung.spring.data.neo4j.repostory; + +import com.baeldung.spring.data.neo4j.model.Book; +import org.springframework.data.neo4j.annotation.Query; +import org.springframework.data.neo4j.repository.GraphRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +@Repository +public interface BookRepository extends GraphRepository { + Book findByTitle(@Param("title") String title); + + @Query("MATCH (m:Book) WHERE m.title =~ ('(?i).*'+{title}+'.*') RETURN m") + Collection findByTitleContaining(@Param("title") String title); + + @Query("MATCH (m:Book)<-[:ACTED_IN]-(a:Person) RETURN m.title as Book, collect(a.name) as cast LIMIT {limit}") + List> graph(@Param("limit") int limit); +} \ No newline at end of file diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookService.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookService.java new file mode 100644 index 0000000000..52323f689b --- /dev/null +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookService.java @@ -0,0 +1,62 @@ +package com.baeldung.spring.data.neo4j.service; + + +import com.baeldung.spring.data.neo4j.model.Book; +import com.baeldung.spring.data.neo4j.repostory.BookRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +@Service +public class BookService { + + @Autowired + private BookRepository bookRepository; + + private Map toD3Format(final Iterator> result) { + List> nodes = new ArrayList>(); + List> rels= new ArrayList>(); + int i=0; + while (result.hasNext()) { + Map row = result.next(); + nodes.add(map("title",row.get("book"),"label","book")); + int target=i; + i++; + for (Object name : (Collection) row.get("cast")) { + Map actor = map("title", name,"label","actor"); + int source = nodes.indexOf(actor); + if (source == -1) { + nodes.add(actor); + source = i++; + } + rels.add(map("source",source,"target",target)); + } + } + return map("nodes", nodes, "links", rels); + } + + private Map map(final String key1, final Object value1, final String key2, final Object value2) { + Map result = new HashMap(2); + result.put(key1,value1); + result.put(key2,value2); + return result; + } + + public Map graph(final int limit) { + Iterator> result = bookRepository.graph(limit).iterator(); + return toD3Format(result); + } + + public Book save(final Book book){ + return bookRepository.save(book); + } + + public Book findBookById(final Long id){ + return bookRepository.findOne(id); + } + + public void deleteAllInGraph(){ + bookRepository.deleteAll(); + } +} \ No newline at end of file From 87496539c705356922c0f102a8de31cdcf0492f0 Mon Sep 17 00:00:00 2001 From: Sameera Nelson Date: Mon, 9 May 2016 00:31:00 +0530 Subject: [PATCH 003/269] Adding example project --- .../java/com/baeldung/spring/data/neo4j/BookServiceTest.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename spring-data-neo4j/src/{main => test}/java/com/baeldung/spring/data/neo4j/BookServiceTest.java (100%) diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/BookServiceTest.java b/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/BookServiceTest.java similarity index 100% rename from spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/BookServiceTest.java rename to spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/BookServiceTest.java From 78bfd55b9b95f5b1008c9484f58655924787c4a6 Mon Sep 17 00:00:00 2001 From: Sameera Nelson Date: Mon, 9 May 2016 00:33:59 +0530 Subject: [PATCH 004/269] Adding example project --- spring-data-neo4j/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-data-neo4j/README.md b/spring-data-neo4j/README.md index 89eae99f05..e62c69f8b9 100644 --- a/spring-data-neo4j/README.md +++ b/spring-data-neo4j/README.md @@ -1,7 +1,7 @@ -## Spring Data Redis +## Spring Data Neo4j ### Relevant Articles: -- [Introduction to Spring Data Redis](http://www.baeldung.com/spring-data-redis-tutorial) +- [Introduction to Spring Data Neo4j](http://www.baeldung.com/spring-data-neo4j-tutorial) ### Build the Project with Tests Running ``` From a317e91d375e9d09aebef69a0c6afad95a3f46ea Mon Sep 17 00:00:00 2001 From: Sameera Nelson Date: Mon, 9 May 2016 00:34:59 +0530 Subject: [PATCH 005/269] Adding example project --- spring-data-neo4j/pom.xml | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/spring-data-neo4j/pom.xml b/spring-data-neo4j/pom.xml index 5d04e0c3b4..72e17250db 100644 --- a/spring-data-neo4j/pom.xml +++ b/spring-data-neo4j/pom.xml @@ -10,7 +10,7 @@ UTF-8 4.2.5.RELEASE - 4.1.1.RELEASE + 4.0.0.RELEASE 0.8.0 @@ -18,19 +18,7 @@ org.springframework.data spring-data-neo4j - ${spring-data-neo4j} - - - - cglib - cglib-nodep - 2.2 - - - - log4j - log4j - 1.2.16 + ${spring-data-neo4j.version} @@ -45,24 +33,29 @@ ${spring.version} + + com.voodoodyne.jackson.jsog + jackson-jsog + 1.1 + compile + + + + log4j + log4j + 1.2.16 + + junit junit 4.12 - test org.springframework spring-test ${spring.version} - test - - - - com.lordofthejars - nosqlunit-redis - ${nosqlunit.version} From 6f95540287139c5754f6d4f5c02065dc3e8f1937 Mon Sep 17 00:00:00 2001 From: Sameera Nelson Date: Fri, 13 May 2016 18:57:52 +0530 Subject: [PATCH 006/269] Adding Book service interface --- .../data/neo4j/service/BookService.java | 64 +++---------------- .../data/neo4j/service/BookServiceImpl.java | 62 ++++++++++++++++++ .../spring/data/neo4j/BookServiceTest.java | 5 +- 3 files changed, 74 insertions(+), 57 deletions(-) create mode 100644 spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookServiceImpl.java diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookService.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookService.java index 52323f689b..f8983dfd16 100644 --- a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookService.java +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookService.java @@ -1,62 +1,18 @@ package com.baeldung.spring.data.neo4j.service; - import com.baeldung.spring.data.neo4j.model.Book; -import com.baeldung.spring.data.neo4j.repostory.BookRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import java.util.*; +import java.util.Map; -@Service -public class BookService { +/** + * Created by SDN on 5/13/2016. + */ +public interface BookService { + Map graph(int limit); - @Autowired - private BookRepository bookRepository; + Book save(Book book); - private Map toD3Format(final Iterator> result) { - List> nodes = new ArrayList>(); - List> rels= new ArrayList>(); - int i=0; - while (result.hasNext()) { - Map row = result.next(); - nodes.add(map("title",row.get("book"),"label","book")); - int target=i; - i++; - for (Object name : (Collection) row.get("cast")) { - Map actor = map("title", name,"label","actor"); - int source = nodes.indexOf(actor); - if (source == -1) { - nodes.add(actor); - source = i++; - } - rels.add(map("source",source,"target",target)); - } - } - return map("nodes", nodes, "links", rels); - } + Book findBookById(Long id); - private Map map(final String key1, final Object value1, final String key2, final Object value2) { - Map result = new HashMap(2); - result.put(key1,value1); - result.put(key2,value2); - return result; - } - - public Map graph(final int limit) { - Iterator> result = bookRepository.graph(limit).iterator(); - return toD3Format(result); - } - - public Book save(final Book book){ - return bookRepository.save(book); - } - - public Book findBookById(final Long id){ - return bookRepository.findOne(id); - } - - public void deleteAllInGraph(){ - bookRepository.deleteAll(); - } -} \ No newline at end of file + void deleteAllInGraph(); +} diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookServiceImpl.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookServiceImpl.java new file mode 100644 index 0000000000..cd50f8b740 --- /dev/null +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookServiceImpl.java @@ -0,0 +1,62 @@ +package com.baeldung.spring.data.neo4j.service; + + +import com.baeldung.spring.data.neo4j.model.Book; +import com.baeldung.spring.data.neo4j.repostory.BookRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +@Service +public class BookServiceImpl implements BookService { + + @Autowired + private BookRepository bookRepository; + + private Map toD3Format(final Iterator> result) { + List> nodes = new ArrayList>(); + List> rels= new ArrayList>(); + int i=0; + while (result.hasNext()) { + Map row = result.next(); + nodes.add(map("title",row.get("book"),"label","book")); + int target=i; + i++; + for (Object name : (Collection) row.get("cast")) { + Map actor = map("title", name,"label","actor"); + int source = nodes.indexOf(actor); + if (source == -1) { + nodes.add(actor); + source = i++; + } + rels.add(map("source",source,"target",target)); + } + } + return map("nodes", nodes, "links", rels); + } + + private Map map(final String key1, final Object value1, final String key2, final Object value2) { + Map result = new HashMap(2); + result.put(key1,value1); + result.put(key2,value2); + return result; + } + + public Map graph(final int limit) { + Iterator> result = bookRepository.graph(limit).iterator(); + return toD3Format(result); + } + + public Book save(final Book book){ + return bookRepository.save(book); + } + + public Book findBookById(final Long id){ + return bookRepository.findOne(id); + } + + public void deleteAllInGraph(){ + bookRepository.deleteAll(); + } +} \ No newline at end of file diff --git a/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/BookServiceTest.java b/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/BookServiceTest.java index 100465838e..9a791f87da 100644 --- a/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/BookServiceTest.java +++ b/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/BookServiceTest.java @@ -21,7 +21,7 @@ public class BookServiceTest { private static final Log LOGGER = LogFactory.getLog(BookServiceTest.class); @Autowired - private BookService bookService; + private BookService bookServiceImpl; @Test public void testSaveBook() { @@ -33,8 +33,7 @@ public class BookServiceTest { book.setReleased(1876); book.setPerson(author1); - bookService.save(book); - final Book savedBook = bookService.findBookById(book.getId()); + final Book savedBook = bookServiceImpl.save(book); assertEquals(book.getTitle(), savedBook.getTitle()); } } From 6e6b4612f8dd914484118cde4fad6f12c879fbc4 Mon Sep 17 00:00:00 2001 From: Sameera Nelson Date: Fri, 13 May 2016 19:58:19 +0530 Subject: [PATCH 007/269] Adding test cases --- .../spring/data/neo4j/model/Person.java | 52 +++++++++++++++++++ .../data/neo4j/repostory/BookRepository.java | 6 --- .../data/neo4j/service/BookService.java | 8 +-- .../data/neo4j/service/BookServiceImpl.java | 44 ++++------------ .../spring/data/neo4j/BookServiceTest.java | 50 ++++++++++++++++-- 5 files changed, 111 insertions(+), 49 deletions(-) create mode 100644 spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/model/Person.java diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/model/Person.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/model/Person.java new file mode 100644 index 0000000000..53444c8f6c --- /dev/null +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/model/Person.java @@ -0,0 +1,52 @@ +package com.baeldung.spring.data.neo4j.model; + +import org.neo4j.ogm.annotation.*; + +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +@NodeEntity +public class Person { + + private static final AtomicLong TS = new AtomicLong(); + + @GraphId + private Long id; + private String name; + private int born; + + @Relationship(type = "AUTHORED_BY") + private List books; + + public Person() { + this.id = TS.incrementAndGet(); + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getBorn() { + return born; + } + + public void setBorn(int born) { + this.born = born; + } + + public List getBooks() { + return books; + } + + public void setBooks(List books) { + this.books = books; + } +} diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/BookRepository.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/BookRepository.java index 5c980b0381..c76d2862fc 100644 --- a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/BookRepository.java +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/BookRepository.java @@ -12,11 +12,5 @@ import java.util.Map; @Repository public interface BookRepository extends GraphRepository { - Book findByTitle(@Param("title") String title); - @Query("MATCH (m:Book) WHERE m.title =~ ('(?i).*'+{title}+'.*') RETURN m") - Collection findByTitleContaining(@Param("title") String title); - - @Query("MATCH (m:Book)<-[:ACTED_IN]-(a:Person) RETURN m.title as Book, collect(a.name) as cast LIMIT {limit}") - List> graph(@Param("limit") int limit); } \ No newline at end of file diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookService.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookService.java index f8983dfd16..daa988c92d 100644 --- a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookService.java +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookService.java @@ -4,14 +4,14 @@ import com.baeldung.spring.data.neo4j.model.Book; import java.util.Map; -/** - * Created by SDN on 5/13/2016. - */ public interface BookService { - Map graph(int limit); Book save(Book book); + void delete(long bookId); + + long bookCount(); + Book findBookById(Long id); void deleteAllInGraph(); diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookServiceImpl.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookServiceImpl.java index cd50f8b740..0c07e4acd9 100644 --- a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookServiceImpl.java +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookServiceImpl.java @@ -14,49 +14,25 @@ public class BookServiceImpl implements BookService { @Autowired private BookRepository bookRepository; - private Map toD3Format(final Iterator> result) { - List> nodes = new ArrayList>(); - List> rels= new ArrayList>(); - int i=0; - while (result.hasNext()) { - Map row = result.next(); - nodes.add(map("title",row.get("book"),"label","book")); - int target=i; - i++; - for (Object name : (Collection) row.get("cast")) { - Map actor = map("title", name,"label","actor"); - int source = nodes.indexOf(actor); - if (source == -1) { - nodes.add(actor); - source = i++; - } - rels.add(map("source",source,"target",target)); - } - } - return map("nodes", nodes, "links", rels); - } - - private Map map(final String key1, final Object value1, final String key2, final Object value2) { - Map result = new HashMap(2); - result.put(key1,value1); - result.put(key2,value2); - return result; - } - - public Map graph(final int limit) { - Iterator> result = bookRepository.graph(limit).iterator(); - return toD3Format(result); - } - public Book save(final Book book){ return bookRepository.save(book); } + public long bookCount(){ + return bookRepository.count(); + } + public Book findBookById(final Long id){ return bookRepository.findOne(id); } + public void delete(final long bookId){ + bookRepository.delete(bookId); + } + public void deleteAllInGraph(){ bookRepository.deleteAll(); } + + } \ No newline at end of file diff --git a/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/BookServiceTest.java b/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/BookServiceTest.java index 9a791f87da..17c75a1921 100644 --- a/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/BookServiceTest.java +++ b/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/BookServiceTest.java @@ -4,8 +4,6 @@ import com.baeldung.spring.data.neo4j.config.LibraryNeo4jConfiguration; import com.baeldung.spring.data.neo4j.model.Book; import com.baeldung.spring.data.neo4j.model.Person; import com.baeldung.spring.data.neo4j.service.BookService; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -13,18 +11,17 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = LibraryNeo4jConfiguration.class) public class BookServiceTest { - private static final Log LOGGER = LogFactory.getLog(BookServiceTest.class); - @Autowired private BookService bookServiceImpl; @Test - public void testSaveBook() { + public void testSavingBook() { final Person author1 = new Person(); author1.setName("Mark Twain"); author1.setBorn(1835); @@ -36,4 +33,47 @@ public class BookServiceTest { final Book savedBook = bookServiceImpl.save(book); assertEquals(book.getTitle(), savedBook.getTitle()); } + + @Test + public void testFindingTheSavedBook() { + final Person author1 = new Person(); + author1.setName("Edgar Allan Poe"); + author1.setBorn(1809); + final Book book = new Book(); + book.setTitle("The Cask of Amontillado"); + book.setReleased(1846); + book.setPerson(author1); + + bookServiceImpl.save(book); + final Book retrievedBook = bookServiceImpl.findBookById(book.getId()); + assertEquals(book.getTitle(), retrievedBook.getTitle()); + } + + @Test + public void testCountTheSavedBooks() { + long bookCount = bookServiceImpl.bookCount(); + assertEquals(bookCount, 2); + } + @Test + public void testDeletingASavedBook() { + final Person author1 = new Person(); + author1.setName("Rider Haggard"); + author1.setBorn(1856); + final Book book = new Book(); + book.setTitle("King Solomon's Mines"); + book.setReleased(1885); + book.setPerson(author1); + + final Book savedBook = bookServiceImpl.save(book); + bookServiceImpl.delete(savedBook.getId()); + final Book retrievedBook = bookServiceImpl.findBookById(book.getId()); + assertNull(retrievedBook); + } + + @Test + public void testDeleteAllSavedBook() { + bookServiceImpl.deleteAllInGraph(); + final long bookCount = bookServiceImpl.bookCount(); + assertEquals(bookCount, 0); + } } From f831d98177e74625e14b57ab35e8b83990b72473 Mon Sep 17 00:00:00 2001 From: Slavisa Baeldung Date: Tue, 31 May 2016 11:24:41 +0200 Subject: [PATCH 008/269] jsf-spring-integration - adding war plugin --- jsf/pom.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/jsf/pom.xml b/jsf/pom.xml index 2f5d315e41..1049bbf38c 100644 --- a/jsf/pom.xml +++ b/jsf/pom.xml @@ -96,6 +96,14 @@ 1.8 + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + false + + @@ -112,5 +120,8 @@ 3.1.0 + + + 2.6 \ No newline at end of file From 85257957554405fba7a7e4817ee801a09cbd5fd3 Mon Sep 17 00:00:00 2001 From: Slavisa Avramovic Date: Thu, 9 Jun 2016 15:00:56 +0200 Subject: [PATCH 009/269] bengi - guava map --- .../org/baeldung/guava/GuavaMapFromSet.java | 136 +++++++++--------- .../baeldung/guava/GuavaMapFromSetTests.java | 90 ++++++------ 2 files changed, 112 insertions(+), 114 deletions(-) diff --git a/guava/src/test/java/org/baeldung/guava/GuavaMapFromSet.java b/guava/src/test/java/org/baeldung/guava/GuavaMapFromSet.java index 602205ff9f..1d19423f7e 100644 --- a/guava/src/test/java/org/baeldung/guava/GuavaMapFromSet.java +++ b/guava/src/test/java/org/baeldung/guava/GuavaMapFromSet.java @@ -11,91 +11,91 @@ import com.google.common.base.Function; public class GuavaMapFromSet extends AbstractMap { - private class SingleEntry implements Entry { - private K key; + private class SingleEntry implements Entry { + private K key; - public SingleEntry( K key) { - this.key = key; - } + public SingleEntry(K key) { + this.key = key; + } - @Override - public K getKey() { - return this.key; - } + @Override + public K getKey() { + return this.key; + } - @Override - public V getValue() { - V value = GuavaMapFromSet.this.cache.get(this.key); - if (value == null) { - value = GuavaMapFromSet.this.function.apply(this.key); - GuavaMapFromSet.this.cache.put(this.key, value); - } - return value; - } + @Override + public V getValue() { + V value = GuavaMapFromSet.this.cache.get(this.key); + if (value == null) { + value = GuavaMapFromSet.this.function.apply(this.key); + GuavaMapFromSet.this.cache.put(this.key, value); + } + return value; + } - @Override - public V setValue( V value) { - throw new UnsupportedOperationException(); - } - } + @Override + public V setValue(V value) { + throw new UnsupportedOperationException(); + } + } - private class MyEntrySet extends AbstractSet> { + private class MyEntrySet extends AbstractSet> { - public class EntryIterator implements Iterator> { - private Iterator inner; + public class EntryIterator implements Iterator> { + private Iterator inner; - public EntryIterator() { - this.inner = MyEntrySet.this.keys.iterator(); - } + public EntryIterator() { + this.inner = MyEntrySet.this.keys.iterator(); + } - @Override - public boolean hasNext() { - return this.inner.hasNext(); - } + @Override + public boolean hasNext() { + return this.inner.hasNext(); + } - @Override - public Map.Entry next() { - K key = this.inner.next(); - return new SingleEntry(key); - } + @Override + public Map.Entry next() { + K key = this.inner.next(); + return new SingleEntry(key); + } - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } - private Set keys; + private Set keys; - public MyEntrySet( Set keys) { - this.keys = keys; - } + public MyEntrySet(Set keys) { + this.keys = keys; + } - @Override - public Iterator> iterator() { - return new EntryIterator(); - } + @Override + public Iterator> iterator() { + return new EntryIterator(); + } - @Override - public int size() { - return this.keys.size(); - } + @Override + public int size() { + return this.keys.size(); + } - } + } - private WeakHashMap cache; - private Set> entries; - private Function function; + private WeakHashMap cache; + private Set> entries; + private Function function; - public GuavaMapFromSet( Set keys, Function function) { - this.function = function; - this.cache = new WeakHashMap(); - this.entries = new MyEntrySet(keys); - } + public GuavaMapFromSet(Set keys, Function function) { + this.function = function; + this.cache = new WeakHashMap(); + this.entries = new MyEntrySet(keys); + } - @Override - public Set> entrySet() { - return this.entries; - } + @Override + public Set> entrySet() { + return this.entries; + } } diff --git a/guava/src/test/java/org/baeldung/guava/GuavaMapFromSetTests.java b/guava/src/test/java/org/baeldung/guava/GuavaMapFromSetTests.java index 9abb5d14a9..7dc4550c09 100644 --- a/guava/src/test/java/org/baeldung/guava/GuavaMapFromSetTests.java +++ b/guava/src/test/java/org/baeldung/guava/GuavaMapFromSetTests.java @@ -13,54 +13,52 @@ import com.google.common.base.Function; public class GuavaMapFromSetTests { - @Test - public void givenStringSet_whenMapsToElementLength_thenCorrect() { - Function function = new Function() { + @Test + public void givenStringSet_whenMapsToElementLength_thenCorrect() { + Function function = new Function() { + @Override + public String apply(Integer from) { + return Integer.toBinaryString(from); + } + }; + Set set = new TreeSet<>(Arrays.asList(32, 64, 128)); + Map map = new GuavaMapFromSet(set, function); + assertTrue(map.get(32).equals("100000") + && map.get(64).equals("1000000") + && map.get(128).equals("10000000")); + } - @Override - public String apply(Integer from) { - return Integer.toBinaryString(from.intValue()); - } - }; - Set set = (Set) new TreeSet(Arrays.asList( - 32, 64, 128)); - Map map = new GuavaMapFromSet(set, - function); - assertTrue(map.get(32).equals("100000") - && map.get(64).equals("1000000") - && map.get(128).equals("10000000")); - } + @Test + public void givenIntSet_whenMapsToElementBinaryValue_thenCorrect() { + Function function = new Function() { - @Test - public void givenIntSet_whenMapsToElementBinaryValue_thenCorrect() { - Function function = new Function() { + @Override + public Integer apply(String from) { + return from.length(); + } + }; + Set set = new TreeSet<>(Arrays.asList( + "four", "three", "twelve")); + Map map = new GuavaMapFromSet(set, + function); + assertTrue(map.get("four") == 4 && map.get("three") == 5 + && map.get("twelve") == 6); + } - @Override - public Integer apply(String from) { - return from.length(); - } - }; - Set set = (Set) new TreeSet(Arrays.asList( - "four", "three", "twelve")); - Map map = new GuavaMapFromSet(set, - function); - assertTrue(map.get("four") == 4 && map.get("three") == 5 - && map.get("twelve") == 6); - } - @Test - public void givenSet_whenNewSetElementAddedAndMappedLive_thenCorrect() { - Function function = new Function() { + @Test + public void givenSet_whenNewSetElementAddedAndMappedLive_thenCorrect() { + Function function = new Function() { - @Override - public Integer apply(String from) { - return from.length(); - } - }; - Set set = (Set) new TreeSet(Arrays.asList( - "four", "three", "twelve")); - Map map = new GuavaMapFromSet(set, - function); - set.add("one"); - assertTrue(map.get("one") == 3 && map.size()==4); - } + @Override + public Integer apply(String from) { + return from.length(); + } + }; + Set set = new TreeSet<>(Arrays.asList( + "four", "three", "twelve")); + Map map = new GuavaMapFromSet(set, + function); + set.add("one"); + assertTrue(map.get("one") == 3 && map.size() == 4); + } } From 27d58fc2007fe0d8e9b0239b7a03d4bf1e80a5c8 Mon Sep 17 00:00:00 2001 From: bdragan Date: Sun, 19 Jun 2016 23:36:22 +0200 Subject: [PATCH 010/269] Code examples for the 'Binary Data Formats in a Spring REST API' article. --- spring-rest/pom.xml | 11 +- .../java/org/baeldung/config/WebConfig.java | 5 +- .../converter/KryoHttpMessageConverter.java | 73 +++ .../web/controller/FooController.java | 6 + .../java/org/baeldung/web/dto/FooProtos.java | 620 ++++++++++++++++++ ...MessageConvertersIntegrationTestsCase.java | 35 + 6 files changed, 748 insertions(+), 2 deletions(-) create mode 100644 spring-rest/src/main/java/org/baeldung/config/converter/KryoHttpMessageConverter.java create mode 100644 spring-rest/src/main/java/org/baeldung/web/dto/FooProtos.java diff --git a/spring-rest/pom.xml b/spring-rest/pom.xml index 767f90a6a6..b05a795c6d 100644 --- a/spring-rest/pom.xml +++ b/spring-rest/pom.xml @@ -155,7 +155,16 @@ spring-test ${spring.version} - + + com.google.protobuf + protobuf-java + 2.6.1 + + + com.esotericsoftware.kryo + kryo + 2.24.0 + diff --git a/spring-rest/src/main/java/org/baeldung/config/WebConfig.java b/spring-rest/src/main/java/org/baeldung/config/WebConfig.java index 999f890ebb..120f1b272a 100644 --- a/spring-rest/src/main/java/org/baeldung/config/WebConfig.java +++ b/spring-rest/src/main/java/org/baeldung/config/WebConfig.java @@ -3,11 +3,13 @@ package org.baeldung.config; import java.text.SimpleDateFormat; import java.util.List; +import org.baeldung.config.converter.KryoHttpMessageConverter; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter; import org.springframework.http.converter.xml.MarshallingHttpMessageConverter; import org.springframework.oxm.xstream.XStreamMarshaller; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @@ -33,7 +35,8 @@ public class WebConfig extends WebMvcConfigurerAdapter { builder.indentOutput(true).dateFormat(new SimpleDateFormat("dd-MM-yyyy hh:mm")); messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build())); // messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build())); - + messageConverters.add(new ProtobufHttpMessageConverter()); + messageConverters.add(new KryoHttpMessageConverter()); super.configureMessageConverters(messageConverters); } diff --git a/spring-rest/src/main/java/org/baeldung/config/converter/KryoHttpMessageConverter.java b/spring-rest/src/main/java/org/baeldung/config/converter/KryoHttpMessageConverter.java new file mode 100644 index 0000000000..371ad333c8 --- /dev/null +++ b/spring-rest/src/main/java/org/baeldung/config/converter/KryoHttpMessageConverter.java @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.baeldung.config.converter; + +import java.io.IOException; + +import org.baeldung.web.dto.Foo; +import org.springframework.http.HttpInputMessage; +import org.springframework.http.HttpOutputMessage; +import org.springframework.http.MediaType; +import org.springframework.http.converter.AbstractHttpMessageConverter; + +import com.esotericsoftware.kryo.Kryo; +import com.esotericsoftware.kryo.io.Input; +import com.esotericsoftware.kryo.io.Output; + +/** + * An {@code HttpMessageConverter} that can read and write Kryo messages. + */ +public class KryoHttpMessageConverter extends AbstractHttpMessageConverter { + + public static final MediaType KRYO = new MediaType("application", "x-kryo"); + + private static final ThreadLocal kryoThreadLocal = new ThreadLocal() { + @Override + protected Kryo initialValue() { + final Kryo kryo = new Kryo(); + kryo.register(Foo.class, 1); + return kryo; + } + }; + + public KryoHttpMessageConverter() { + super(KRYO); + } + + @Override + protected boolean supports(final Class clazz) { + return Object.class.isAssignableFrom(clazz); + } + + @Override + protected Object readInternal(final Class clazz, final HttpInputMessage inputMessage) throws IOException { + final Input input = new Input(inputMessage.getBody()); + return kryoThreadLocal.get().readClassAndObject(input); + } + + @Override + protected void writeInternal(final Object object, final HttpOutputMessage outputMessage) throws IOException { + final Output output = new Output(outputMessage.getBody()); + kryoThreadLocal.get().writeClassAndObject(output, object); + output.flush(); + } + + @Override + protected MediaType getDefaultContentType(final Object object) { + return KRYO; + } +} diff --git a/spring-rest/src/main/java/org/baeldung/web/controller/FooController.java b/spring-rest/src/main/java/org/baeldung/web/controller/FooController.java index ed6b150403..386c64bb09 100644 --- a/spring-rest/src/main/java/org/baeldung/web/controller/FooController.java +++ b/spring-rest/src/main/java/org/baeldung/web/controller/FooController.java @@ -4,6 +4,7 @@ import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; import static org.apache.commons.lang3.RandomStringUtils.randomNumeric; import org.baeldung.web.dto.Foo; +import org.baeldung.web.dto.FooProtos; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; @@ -38,4 +39,9 @@ public class FooController { return foo; } + @RequestMapping(method = RequestMethod.GET, value = "/foos/{id}", produces = { "application/x-protobuf" }) + @ResponseBody + public FooProtos.Foo findProtoById(@PathVariable final long id) { + return FooProtos.Foo.newBuilder().setId(1).setName("Foo Name").build(); + } } diff --git a/spring-rest/src/main/java/org/baeldung/web/dto/FooProtos.java b/spring-rest/src/main/java/org/baeldung/web/dto/FooProtos.java new file mode 100644 index 0000000000..61251ea33a --- /dev/null +++ b/spring-rest/src/main/java/org/baeldung/web/dto/FooProtos.java @@ -0,0 +1,620 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: FooProtos.proto + +package org.baeldung.web.dto; + +public final class FooProtos { + private FooProtos() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + } + public interface FooOrBuilder extends + // @@protoc_insertion_point(interface_extends:baeldung.Foo) + com.google.protobuf.MessageOrBuilder { + + /** + * required int64 id = 1; + */ + boolean hasId(); + /** + * required int64 id = 1; + */ + long getId(); + + /** + * required string name = 2; + */ + boolean hasName(); + /** + * required string name = 2; + */ + java.lang.String getName(); + /** + * required string name = 2; + */ + com.google.protobuf.ByteString + getNameBytes(); + } + /** + * Protobuf type {@code baeldung.Foo} + */ + public static final class Foo extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:baeldung.Foo) + FooOrBuilder { + // Use Foo.newBuilder() to construct. + private Foo(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private Foo(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final Foo defaultInstance; + public static Foo getDefaultInstance() { + return defaultInstance; + } + + public Foo getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private Foo( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + id_ = input.readInt64(); + break; + } + case 18: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000002; + name_ = bs; + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.baeldung.web.dto.FooProtos.internal_static_baeldung_Foo_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.baeldung.web.dto.FooProtos.internal_static_baeldung_Foo_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.baeldung.web.dto.FooProtos.Foo.class, org.baeldung.web.dto.FooProtos.Foo.Builder.class); + } + + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public Foo parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new Foo(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int ID_FIELD_NUMBER = 1; + private long id_; + /** + * required int64 id = 1; + */ + public boolean hasId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required int64 id = 1; + */ + public long getId() { + return id_; + } + + public static final int NAME_FIELD_NUMBER = 2; + private java.lang.Object name_; + /** + * required string name = 2; + */ + public boolean hasName() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string name = 2; + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + name_ = s; + } + return s; + } + } + /** + * required string name = 2; + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private void initFields() { + id_ = 0L; + name_ = ""; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasId()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasName()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeInt64(1, id_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(2, getNameBytes()); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeInt64Size(1, id_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(2, getNameBytes()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static org.baeldung.web.dto.FooProtos.Foo parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.baeldung.web.dto.FooProtos.Foo parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.baeldung.web.dto.FooProtos.Foo parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.baeldung.web.dto.FooProtos.Foo parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.baeldung.web.dto.FooProtos.Foo parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.baeldung.web.dto.FooProtos.Foo parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static org.baeldung.web.dto.FooProtos.Foo parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static org.baeldung.web.dto.FooProtos.Foo parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static org.baeldung.web.dto.FooProtos.Foo parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.baeldung.web.dto.FooProtos.Foo parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.baeldung.web.dto.FooProtos.Foo prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code baeldung.Foo} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:baeldung.Foo) + org.baeldung.web.dto.FooProtos.FooOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.baeldung.web.dto.FooProtos.internal_static_baeldung_Foo_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.baeldung.web.dto.FooProtos.internal_static_baeldung_Foo_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.baeldung.web.dto.FooProtos.Foo.class, org.baeldung.web.dto.FooProtos.Foo.Builder.class); + } + + // Construct using org.baeldung.web.dto.FooProtos.Foo.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + id_ = 0L; + bitField0_ = (bitField0_ & ~0x00000001); + name_ = ""; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.baeldung.web.dto.FooProtos.internal_static_baeldung_Foo_descriptor; + } + + public org.baeldung.web.dto.FooProtos.Foo getDefaultInstanceForType() { + return org.baeldung.web.dto.FooProtos.Foo.getDefaultInstance(); + } + + public org.baeldung.web.dto.FooProtos.Foo build() { + org.baeldung.web.dto.FooProtos.Foo result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.baeldung.web.dto.FooProtos.Foo buildPartial() { + org.baeldung.web.dto.FooProtos.Foo result = new org.baeldung.web.dto.FooProtos.Foo(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.id_ = id_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.name_ = name_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.baeldung.web.dto.FooProtos.Foo) { + return mergeFrom((org.baeldung.web.dto.FooProtos.Foo)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.baeldung.web.dto.FooProtos.Foo other) { + if (other == org.baeldung.web.dto.FooProtos.Foo.getDefaultInstance()) return this; + if (other.hasId()) { + setId(other.getId()); + } + if (other.hasName()) { + bitField0_ |= 0x00000002; + name_ = other.name_; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + if (!hasId()) { + + return false; + } + if (!hasName()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.baeldung.web.dto.FooProtos.Foo parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.baeldung.web.dto.FooProtos.Foo) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private long id_ ; + /** + * required int64 id = 1; + */ + public boolean hasId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required int64 id = 1; + */ + public long getId() { + return id_; + } + /** + * required int64 id = 1; + */ + public Builder setId(long value) { + bitField0_ |= 0x00000001; + id_ = value; + onChanged(); + return this; + } + /** + * required int64 id = 1; + */ + public Builder clearId() { + bitField0_ = (bitField0_ & ~0x00000001); + id_ = 0L; + onChanged(); + return this; + } + + private java.lang.Object name_ = ""; + /** + * required string name = 2; + */ + public boolean hasName() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string name = 2; + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + name_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string name = 2; + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string name = 2; + */ + public Builder setName( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + name_ = value; + onChanged(); + return this; + } + /** + * required string name = 2; + */ + public Builder clearName() { + bitField0_ = (bitField0_ & ~0x00000002); + name_ = getDefaultInstance().getName(); + onChanged(); + return this; + } + /** + * required string name = 2; + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + name_ = value; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:baeldung.Foo) + } + + static { + defaultInstance = new Foo(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:baeldung.Foo) + } + + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_baeldung_Foo_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_baeldung_Foo_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\017FooProtos.proto\022\010baeldung\"\037\n\003Foo\022\n\n\002id" + + "\030\001 \002(\003\022\014\n\004name\030\002 \002(\tB!\n\024org.baeldung.web" + + ".dtoB\tFooProtos" + }; + com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = + new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() { + public com.google.protobuf.ExtensionRegistry assignDescriptors( + com.google.protobuf.Descriptors.FileDescriptor root) { + descriptor = root; + return null; + } + }; + com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }, assigner); + internal_static_baeldung_Foo_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_baeldung_Foo_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_baeldung_Foo_descriptor, + new java.lang.String[] { "Id", "Name", }); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/spring-rest/src/test/java/org/baeldung/web/test/SpringHttpMessageConvertersIntegrationTestsCase.java b/spring-rest/src/test/java/org/baeldung/web/test/SpringHttpMessageConvertersIntegrationTestsCase.java index c21641ca22..1536f14bc8 100644 --- a/spring-rest/src/test/java/org/baeldung/web/test/SpringHttpMessageConvertersIntegrationTestsCase.java +++ b/spring-rest/src/test/java/org/baeldung/web/test/SpringHttpMessageConvertersIntegrationTestsCase.java @@ -7,7 +7,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.baeldung.config.converter.KryoHttpMessageConverter; import org.baeldung.web.dto.Foo; +import org.baeldung.web.dto.FooProtos; import org.junit.Assert; import org.junit.Test; import org.springframework.http.HttpEntity; @@ -17,6 +19,7 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter; import org.springframework.http.converter.xml.MarshallingHttpMessageConverter; import org.springframework.oxm.xstream.XStreamMarshaller; import org.springframework.web.client.RestTemplate; @@ -94,6 +97,38 @@ public class SpringHttpMessageConvertersIntegrationTestsCase { Assert.assertEquals(resource.getId(), fooResponse.getId()); } + @Test + public void givenConsumingProtobuf_whenReadingTheFoo_thenCorrect() { + final String URI = BASE_URI + "foos/{id}"; + + final RestTemplate restTemplate = new RestTemplate(); + restTemplate.setMessageConverters(Arrays.asList(new ProtobufHttpMessageConverter())); + final HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Arrays.asList(ProtobufHttpMessageConverter.PROTOBUF)); + final HttpEntity entity = new HttpEntity(headers); + + final ResponseEntity response = restTemplate.exchange(URI, HttpMethod.GET, entity, FooProtos.Foo.class, "1"); + final FooProtos.Foo resource = response.getBody(); + + assertThat(resource, notNullValue()); + } + + @Test + public void givenConsumingKryo_whenReadingTheFoo_thenCorrect() { + final String URI = BASE_URI + "foos/{id}"; + + final RestTemplate restTemplate = new RestTemplate(); + restTemplate.setMessageConverters(Arrays.asList(new KryoHttpMessageConverter())); + final HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Arrays.asList(KryoHttpMessageConverter.KRYO)); + final HttpEntity entity = new HttpEntity(headers); + + final ResponseEntity response = restTemplate.exchange(URI, HttpMethod.GET, entity, Foo.class, "1"); + final Foo resource = response.getBody(); + + assertThat(resource, notNullValue()); + } + // UTIL private List> getMessageConverters() { From 57411aa1c297b90aa20b51d36411a7310529d93a Mon Sep 17 00:00:00 2001 From: bdragan Date: Sun, 19 Jun 2016 23:43:13 +0200 Subject: [PATCH 011/269] Removed copy-pasted comments. --- .../converter/KryoHttpMessageConverter.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/spring-rest/src/main/java/org/baeldung/config/converter/KryoHttpMessageConverter.java b/spring-rest/src/main/java/org/baeldung/config/converter/KryoHttpMessageConverter.java index 371ad333c8..7e63a3ba9e 100644 --- a/spring-rest/src/main/java/org/baeldung/config/converter/KryoHttpMessageConverter.java +++ b/spring-rest/src/main/java/org/baeldung/config/converter/KryoHttpMessageConverter.java @@ -1,19 +1,3 @@ -/* - * Copyright 2002-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - package org.baeldung.config.converter; import java.io.IOException; From 3d0b89a66a8642c162500f5deac62ec091d3635a Mon Sep 17 00:00:00 2001 From: Ivan Paolillo Date: Tue, 21 Jun 2016 18:02:14 +0200 Subject: [PATCH 012/269] Add JSON Schema validation --- json/.classpath | 32 +++++++++++++++++++ json/.project | 23 +++++++++++++ json/pom.xml | 25 +++++++++++++++ .../baeldung/json/schema/JSONSchemaTest.java | 32 +++++++++++++++++++ json/src/test/resources/product.json | 5 +++ json/src/test/resources/schema.json | 22 +++++++++++++ 6 files changed, 139 insertions(+) create mode 100644 json/.classpath create mode 100644 json/.project create mode 100644 json/pom.xml create mode 100644 json/src/test/java/org/baeldung/json/schema/JSONSchemaTest.java create mode 100644 json/src/test/resources/product.json create mode 100644 json/src/test/resources/schema.json diff --git a/json/.classpath b/json/.classpath new file mode 100644 index 0000000000..4f9b9b5af7 --- /dev/null +++ b/json/.classpath @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/json/.project b/json/.project new file mode 100644 index 0000000000..8424469786 --- /dev/null +++ b/json/.project @@ -0,0 +1,23 @@ + + + json + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/json/pom.xml b/json/pom.xml new file mode 100644 index 0000000000..47f1f25aa2 --- /dev/null +++ b/json/pom.xml @@ -0,0 +1,25 @@ + + 4.0.0 + org.baeldung + json + 0.0.1-SNAPSHOT + + + + + org.everit.json + org.everit.json.schema + 1.3.0 + + + + junit + junit + 4.12 + test + + + + + diff --git a/json/src/test/java/org/baeldung/json/schema/JSONSchemaTest.java b/json/src/test/java/org/baeldung/json/schema/JSONSchemaTest.java new file mode 100644 index 0000000000..5e8f024ac3 --- /dev/null +++ b/json/src/test/java/org/baeldung/json/schema/JSONSchemaTest.java @@ -0,0 +1,32 @@ +package org.baeldung.json.schema; + +import org.everit.json.schema.Schema; +import org.everit.json.schema.ValidationException; +import org.everit.json.schema.loader.SchemaLoader; + +import org.json.JSONObject; +import org.json.JSONTokener; +import org.junit.Test; + +public class JSONSchemaTest { + + @Test + public void validateJSON() { + + JSONObject jsonSchema = new JSONObject(new JSONTokener(JSONSchemaTest.class.getResourceAsStream("/schema.json"))); + JSONObject jsonSubject = new JSONObject(new JSONTokener(JSONSchemaTest.class.getResourceAsStream("/product.json"))); + + Schema schema = SchemaLoader.load(jsonSchema); + + try { + + schema.validate(jsonSubject); + } + + catch (ValidationException e) { + + System.out.println(e.getMessage()); + e.getCausingExceptions().stream().map(ValidationException::getMessage).forEach(System.out::println); + } + } +} diff --git a/json/src/test/resources/product.json b/json/src/test/resources/product.json new file mode 100644 index 0000000000..7c55d8c7a5 --- /dev/null +++ b/json/src/test/resources/product.json @@ -0,0 +1,5 @@ +{ + "id": 1, + "name": "Lampshade", + "price": 0 +} diff --git a/json/src/test/resources/schema.json b/json/src/test/resources/schema.json new file mode 100644 index 0000000000..7cf99d76e0 --- /dev/null +++ b/json/src/test/resources/schema.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Product", + "description": "A product from the catalog", + "type": "object", + "properties": { + "id": { + "description": "The unique identifier for a product", + "type": "integer" + }, + "name": { + "description": "Name of the product", + "type": "string" + }, + "price": { + "type": "number", + "minimum": 0, + "exclusiveMinimum": true + } + }, + "required": ["id", "name", "price"] +} From 3dbc073fa3763e3f60c30bffdd1695a9ca79c2dc Mon Sep 17 00:00:00 2001 From: Ivan Paolillo Date: Tue, 21 Jun 2016 18:04:13 +0200 Subject: [PATCH 013/269] Add gatling example --- gatling/.cache-tests | 153 +++++++++++++++++++++++++++++++++++++++++++ gatling/.classpath | 32 +++++++++ gatling/.project | 24 +++++++ 3 files changed, 209 insertions(+) create mode 100644 gatling/.cache-tests create mode 100644 gatling/.classpath create mode 100644 gatling/.project diff --git a/gatling/.cache-tests b/gatling/.cache-tests new file mode 100644 index 0000000000..9d7ddf685f --- /dev/null +++ b/gatling/.cache-tests @@ -0,0 +1,153 @@ +format version: 5 +output mode: +1 items +0 -> multiple +output directories: +2 items +C:\develop\git\tutorials\gatling\src\test\resources -> C:\develop\git\tutorials\gatling\target\test-classes +C:\develop\git\tutorials\gatling\src\test\scala -> C:\develop\git\tutorials\gatling\target\test-classes +compile options: +8 items +0 -> -javabootclasspath +1 -> C:\develop\Java\jdk1.8.0_77\jre\lib\resources.jar;C:\develop\Java\jdk1.8.0_77\jre\lib\rt.jar;C:\develop\Java\jdk1.8.0_77\jre\lib\jsse.jar;C:\develop\Java\jdk1.8.0_77\jre\lib\jce.jar;C:\develop\Java\jdk1.8.0_77\jre\lib\charsets.jar;C:\develop\Java\jdk1.8.0_77\jre\lib\jfr.jar;C:\develop\Java\jdk1.8.0_77\jre\lib\ext\access-bridge-64.jar;C:\develop\Java\jdk1.8.0_77\jre\lib\ext\cldrdata.jar;C:\develop\Java\jdk1.8.0_77\jre\lib\ext\dnsns.jar;C:\develop\Java\jdk1.8.0_77\jre\lib\ext\jaccess.jar;C:\develop\Java\jdk1.8.0_77\jre\lib\ext\jfxrt.jar;C:\develop\Java\jdk1.8.0_77\jre\lib\ext\localedata.jar;C:\develop\Java\jdk1.8.0_77\jre\lib\ext\nashorn.jar;C:\develop\Java\jdk1.8.0_77\jre\lib\ext\sunec.jar;C:\develop\Java\jdk1.8.0_77\jre\lib\ext\sunjce_provider.jar;C:\develop\Java\jdk1.8.0_77\jre\lib\ext\sunmscapi.jar;C:\develop\Java\jdk1.8.0_77\jre\lib\ext\sunpkcs11.jar;C:\develop\Java\jdk1.8.0_77\jre\lib\ext\zipfs.jar +2 -> -javaextdirs +3 -> +4 -> -bootclasspath +5 -> C:\develop\IDE\sts-bundle\sts-3.7.3.RELEASE\plugins\org.scala-lang.scala-library_2.11.8.v20160304-115712-1706a37eb8.jar +6 -> -encoding +7 -> UTF-8 +javac options: +0 items +compiler version: +1 items +0 -> 2.11.8 +compile order: +1 items +0 -> Mixed +name hashing: +1 items +0 -> false +products: +9 items +C:\develop\git\tutorials\gatling\src\test\scala\Engine.scala -> C:\develop\git\tutorials\gatling\target\test-classes\Engine$.class +C:\develop\git\tutorials\gatling\src\test\scala\Engine.scala -> C:\develop\git\tutorials\gatling\target\test-classes\Engine$delayedInit$body.class +C:\develop\git\tutorials\gatling\src\test\scala\Engine.scala -> C:\develop\git\tutorials\gatling\target\test-classes\Engine.class +C:\develop\git\tutorials\gatling\src\test\scala\IDEPathHelper.scala -> C:\develop\git\tutorials\gatling\target\test-classes\IDEPathHelper$.class +C:\develop\git\tutorials\gatling\src\test\scala\IDEPathHelper.scala -> C:\develop\git\tutorials\gatling\target\test-classes\IDEPathHelper.class +C:\develop\git\tutorials\gatling\src\test\scala\org\baeldung\RecordedSimulation.scala -> C:\develop\git\tutorials\gatling\target\test-classes\org\baeldung\RecordedSimulation.class +C:\develop\git\tutorials\gatling\src\test\scala\Recorder.scala -> C:\develop\git\tutorials\gatling\target\test-classes\Recorder$.class +C:\develop\git\tutorials\gatling\src\test\scala\Recorder.scala -> C:\develop\git\tutorials\gatling\target\test-classes\Recorder$delayedInit$body.class +C:\develop\git\tutorials\gatling\src\test\scala\Recorder.scala -> C:\develop\git\tutorials\gatling\target\test-classes\Recorder.class +binary dependencies: +15 items +C:\develop\git\tutorials\gatling\src\test\scala\Engine.scala -> C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-app\2.2.0\gatling-app-2.2.0.jar +C:\develop\git\tutorials\gatling\src\test\scala\Engine.scala -> C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-core\2.2.0\gatling-core-2.2.0.jar +C:\develop\git\tutorials\gatling\src\test\scala\Engine.scala -> C:\develop\IDE\sts-bundle\sts-3.7.3.RELEASE\plugins\org.scala-lang.scala-library_2.11.8.v20160304-115712-1706a37eb8.jar +C:\develop\git\tutorials\gatling\src\test\scala\Engine.scala -> C:\develop\Java\jdk1.8.0_77\jre\lib\rt.jar +C:\develop\git\tutorials\gatling\src\test\scala\IDEPathHelper.scala -> C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-commons\2.2.0\gatling-commons-2.2.0.jar +C:\develop\git\tutorials\gatling\src\test\scala\IDEPathHelper.scala -> C:\develop\Java\jdk1.8.0_77\jre\lib\rt.jar +C:\develop\git\tutorials\gatling\src\test\scala\org\baeldung\RecordedSimulation.scala -> C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-commons\2.2.0\gatling-commons-2.2.0.jar +C:\develop\git\tutorials\gatling\src\test\scala\org\baeldung\RecordedSimulation.scala -> C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-core\2.2.0\gatling-core-2.2.0.jar +C:\develop\git\tutorials\gatling\src\test\scala\org\baeldung\RecordedSimulation.scala -> C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-http\2.2.0\gatling-http-2.2.0.jar +C:\develop\git\tutorials\gatling\src\test\scala\org\baeldung\RecordedSimulation.scala -> C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-jdbc\2.2.0\gatling-jdbc-2.2.0.jar +C:\develop\git\tutorials\gatling\src\test\scala\org\baeldung\RecordedSimulation.scala -> C:\develop\IDE\sts-bundle\sts-3.7.3.RELEASE\plugins\org.scala-lang.scala-library_2.11.8.v20160304-115712-1706a37eb8.jar +C:\develop\git\tutorials\gatling\src\test\scala\org\baeldung\RecordedSimulation.scala -> C:\develop\Java\jdk1.8.0_77\jre\lib\rt.jar +C:\develop\git\tutorials\gatling\src\test\scala\Recorder.scala -> C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-recorder\2.2.0\gatling-recorder-2.2.0.jar +C:\develop\git\tutorials\gatling\src\test\scala\Recorder.scala -> C:\develop\IDE\sts-bundle\sts-3.7.3.RELEASE\plugins\org.scala-lang.scala-library_2.11.8.v20160304-115712-1706a37eb8.jar +C:\develop\git\tutorials\gatling\src\test\scala\Recorder.scala -> C:\develop\Java\jdk1.8.0_77\jre\lib\rt.jar +direct source dependencies: +2 items +C:\develop\git\tutorials\gatling\src\test\scala\Engine.scala -> C:\develop\git\tutorials\gatling\src\test\scala\IDEPathHelper.scala +C:\develop\git\tutorials\gatling\src\test\scala\Recorder.scala -> C:\develop\git\tutorials\gatling\src\test\scala\IDEPathHelper.scala +direct external dependencies: +0 items +public inherited source dependencies: +0 items +public inherited external dependencies: +0 items +member reference internal dependencies: +0 items +member reference external dependencies: +0 items +inheritance internal dependencies: +0 items +inheritance external dependencies: +0 items +class names: +9 items +C:\develop\git\tutorials\gatling\src\test\scala\Engine.scala -> Engine +C:\develop\git\tutorials\gatling\src\test\scala\Engine.scala -> Engine$ +C:\develop\git\tutorials\gatling\src\test\scala\Engine.scala -> Engine$delayedInit$body +C:\develop\git\tutorials\gatling\src\test\scala\IDEPathHelper.scala -> IDEPathHelper +C:\develop\git\tutorials\gatling\src\test\scala\IDEPathHelper.scala -> IDEPathHelper$ +C:\develop\git\tutorials\gatling\src\test\scala\org\baeldung\RecordedSimulation.scala -> org.baeldung.RecordedSimulation +C:\develop\git\tutorials\gatling\src\test\scala\Recorder.scala -> Recorder +C:\develop\git\tutorials\gatling\src\test\scala\Recorder.scala -> Recorder$ +C:\develop\git\tutorials\gatling\src\test\scala\Recorder.scala -> Recorder$delayedInit$body +used names: +0 items +product stamps: +9 items +C:\develop\git\tutorials\gatling\target\test-classes\Engine$.class -> lastModified(1465396871370) +C:\develop\git\tutorials\gatling\target\test-classes\Engine$delayedInit$body.class -> lastModified(1465396871373) +C:\develop\git\tutorials\gatling\target\test-classes\Engine.class -> lastModified(1465396871361) +C:\develop\git\tutorials\gatling\target\test-classes\IDEPathHelper$.class -> lastModified(1465396871385) +C:\develop\git\tutorials\gatling\target\test-classes\IDEPathHelper.class -> lastModified(1465396871376) +C:\develop\git\tutorials\gatling\target\test-classes\org\baeldung\RecordedSimulation.class -> lastModified(1465396871404) +C:\develop\git\tutorials\gatling\target\test-classes\Recorder$.class -> lastModified(1465396871393) +C:\develop\git\tutorials\gatling\target\test-classes\Recorder$delayedInit$body.class -> lastModified(1465396871396) +C:\develop\git\tutorials\gatling\target\test-classes\Recorder.class -> lastModified(1465396871388) +source stamps: +4 items +C:\develop\git\tutorials\gatling\src\test\scala\Engine.scala -> hash(2eceb2c4a888a866d01f75f215a951e46b5e115d) +C:\develop\git\tutorials\gatling\src\test\scala\IDEPathHelper.scala -> hash(a3e6002ad6e383bea2cb96ec7ffb22ba92b58222) +C:\develop\git\tutorials\gatling\src\test\scala\org\baeldung\RecordedSimulation.scala -> hash(6bc105187fe6b04ac3d39df88ed51f1955655362) +C:\develop\git\tutorials\gatling\src\test\scala\Recorder.scala -> hash(f4fad197bc0e77df05ac1f50d3fa7f2f04fb288d) +binary stamps: +8 items +C:\develop\IDE\sts-bundle\sts-3.7.3.RELEASE\plugins\org.scala-lang.scala-library_2.11.8.v20160304-115712-1706a37eb8.jar -> lastModified(1463581376873) +C:\develop\Java\jdk1.8.0_77\jre\lib\rt.jar -> lastModified(1460466041763) +C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-app\2.2.0\gatling-app-2.2.0.jar -> lastModified(1463577683111) +C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-commons\2.2.0\gatling-commons-2.2.0.jar -> lastModified(1463577434095) +C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-core\2.2.0\gatling-core-2.2.0.jar -> lastModified(1463577425041) +C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-http\2.2.0\gatling-http-2.2.0.jar -> lastModified(1463577691216) +C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-jdbc\2.2.0\gatling-jdbc-2.2.0.jar -> lastModified(1463577767127) +C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-recorder\2.2.0\gatling-recorder-2.2.0.jar -> lastModified(1463577812366) +class names: +8 items +C:\develop\IDE\sts-bundle\sts-3.7.3.RELEASE\plugins\org.scala-lang.scala-library_2.11.8.v20160304-115712-1706a37eb8.jar -> scala.reflect.ClassTag$ +C:\develop\Java\jdk1.8.0_77\jre\lib\rt.jar -> java.lang.Object +C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-app\2.2.0\gatling-app-2.2.0.jar -> io.gatling.app.Gatling$ +C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-commons\2.2.0\gatling-commons-2.2.0.jar -> io.gatling.commons.util.TypeCaster$ +C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-core\2.2.0\gatling-core-2.2.0.jar -> io.gatling.core.scenario.Simulation +C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-http\2.2.0\gatling-http-2.2.0.jar -> io.gatling.http.request.builder.HttpRequestBuilder$ +C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-jdbc\2.2.0\gatling-jdbc-2.2.0.jar -> io.gatling.jdbc.Predef$ +C:\Users\Ivan Paolillo\.m2\repository\io\gatling\gatling-recorder\2.2.0\gatling-recorder-2.2.0.jar -> io.gatling.recorder.GatlingRecorder$ +internal apis: +4 items +C:\develop\git\tutorials\gatling\src\test\scala\Engine.scala -> +rO0ABXNyABB4c2J0aS5hcGkuU291cmNlFlpwRASfbtoCAAZJAAdhcGlIYXNoWgAIaGFzTWFjcm9MABhfaW50ZXJuYWxPbmx5X25hbWVIYXNoZXN0ACRMeHNidGkvYXBpL19pbnRlcm5hbE9ubHlfTmFtZUhhc2hlcztMAANhcGl0ABVMeHNidGkvYXBpL1NvdXJjZUFQSTtMAAtjb21waWxhdGlvbnQAF0x4c2J0aS9hcGkvQ29tcGlsYXRpb247WwAEaGFzaHQAAltCeHA7lBuUAHNyACJ4c2J0aS5hcGkuX2ludGVybmFsT25seV9OYW1lSGFzaGVzVNq+mfrU7EwCAAJbAA9pbXBsaWNpdE1lbWJlcnN0ACNbTHhzYnRpL2FwaS9faW50ZXJuYWxPbmx5X05hbWVIYXNoO1sADnJlZ3VsYXJNZW1iZXJzcQB+AAd4cHVyACNbTHhzYnRpLmFwaS5faW50ZXJuYWxPbmx5X05hbWVIYXNoO0lagLbdlov0AgAAeHAAAAAAdXEAfgAJAAAAAHNyABN4c2J0aS5hcGkuU291cmNlQVBJuV6n+SkjOKQCAAJbAAtkZWZpbml0aW9uc3QAF1tMeHNidGkvYXBpL0RlZmluaXRpb247WwAIcGFja2FnZXN0ABRbTHhzYnRpL2FwaS9QYWNrYWdlO3hwdXIAF1tMeHNidGkuYXBpLkRlZmluaXRpb247iMlc57TjXg4CAAB4cAAAAAFzcgATeHNidGkuYXBpLkNsYXNzTGlrZYM0HKHfsJdsAgAETAAOZGVmaW5pdGlvblR5cGV0ABpMeHNidGkvYXBpL0RlZmluaXRpb25UeXBlO1sAEHNhdmVkQW5ub3RhdGlvbnN0ABNbTGphdmEvbGFuZy9TdHJpbmc7TAAIc2VsZlR5cGV0ABBMeHNidGkvYXBpL0xhenk7TAAJc3RydWN0dXJlcQB+ABV4cgAheHNidGkuYXBpLlBhcmFtZXRlcml6ZWREZWZpbml0aW9u+RFusdVQPOICAAFbAA50eXBlUGFyYW1ldGVyc3QAGltMeHNidGkvYXBpL1R5cGVQYXJhbWV0ZXI7eHIAFHhzYnRpLmFwaS5EZWZpbml0aW9uhyob6HFC40YCAARMAAZhY2Nlc3N0ABJMeHNidGkvYXBpL0FjY2VzcztbAAthbm5vdGF0aW9uc3QAF1tMeHNidGkvYXBpL0Fubm90YXRpb247TAAJbW9kaWZpZXJzdAAVTHhzYnRpL2FwaS9Nb2RpZmllcnM7TAAEbmFtZXQAEkxqYXZhL2xhbmcvU3RyaW5nO3hwc3IAEHhzYnRpLmFwaS5QdWJsaWO6WD2ubC1gQgIAAHhyABB4c2J0aS5hcGkuQWNjZXNz3WKa+B1jMUgCAAB4cHVyABdbTHhzYnRpLmFwaS5Bbm5vdGF0aW9uO+uX6xkQ9o1IAgAAeHAAAAAAc3IAE3hzYnRpLmFwaS5Nb2RpZmllcnPHERMhaZzcJAIAAUIABWZsYWdzeHAAdAAGRW5naW5ldXIAGltMeHNidGkuYXBpLlR5cGVQYXJhbWV0ZXI72W0mDyid8rYCAAB4cAAAAAB+cgAYeHNidGkuYXBpLkRlZmluaXRpb25UeXBlAAAAAAAAAAASAAB4cgAOamF2YS5sYW5nLkVudW0AAAAAAAAAABIAAHhwdAAGTW9kdWxldXIAE1tMamF2YS5sYW5nLlN0cmluZzut0lbn6R17RwIAAHhwAAAAAnQAEHNjYWxhLmRlcHJlY2F0ZWR0ABpzY2FsYS5kZXByZWNhdGVkT3ZlcnJpZGluZ3NyABN4c2J0aS5TYWZlTGF6eSRJbXBsO5FPEfRFTMkCAANaAAhiaXRtYXAkMEwAAl90dAASTGphdmEvbGFuZy9PYmplY3Q7TAAEZXZhbHQAEUxzY2FsYS9GdW5jdGlvbjA7eHIAFnhzYnRpLmFwaS5BYnN0cmFjdExhennTd7UBX7vnoAIAAHhwAXNyABN4c2J0aS5hcGkuRW1wdHlUeXBlvP2eRkk7iSQCAAB4cgAUeHNidGkuYXBpLlNpbXBsZVR5cGVyeGKIISO/QAIAAHhyAA54c2J0aS5hcGkuVHlwZT9q2SEWSarKAgAAeHBwc3EAfgAwAXNyABN4c2J0aS5hcGkuU3RydWN0dXJlqar5gJNv2AACAANMAAhkZWNsYXJlZHEAfgAVTAAJaW5oZXJpdGVkcQB+ABVMAAdwYXJlbnRzcQB+ABV4cQB+ADdzcQB+ADABdXEAfgAQAAAAAHBzcQB+ADABdXEAfgAQAAAAAXNyAA14c2J0aS5hcGkuRGVmUr6f4ny0NmkCAAJMAApyZXR1cm5UeXBldAAQTHhzYnRpL2FwaS9UeXBlO1sAD3ZhbHVlUGFyYW1ldGVyc3QAGltMeHNidGkvYXBpL1BhcmFtZXRlckxpc3Q7eHEAfgAWcQB+ACB1cQB+ACEAAAABc3IAFHhzYnRpLmFwaS5Bbm5vdGF0aW9u3g6BovZcCrICAAJbAAlhcmd1bWVudHN0AB9bTHhzYnRpL2FwaS9Bbm5vdGF0aW9uQXJndW1lbnQ7TAAEYmFzZXEAfgBBeHB1cgAfW0x4c2J0aS5hcGkuQW5ub3RhdGlvbkFyZ3VtZW50O1Gdpo84JQ94AgAAeHAAAAABc3IAHHhzYnRpLmFwaS5Bbm5vdGF0aW9uQXJndW1lbnTWRbHYAxsXfAIAAkwABG5hbWVxAH4AHEwABXZhbHVlcQB+ABx4cHQAAHQAKigibWFpbiBzaG91bGQgbm90IGJlIG92ZXJyaWRkZW4iLCIyLjExLjAiKXNyABR4c2J0aS5hcGkuUHJvamVjdGlvbvPSjVTpRaQtAgACTAACaWRxAH4AHEwABnByZWZpeHQAFkx4c2J0aS9hcGkvU2ltcGxlVHlwZTt4cQB+ADZ0ABRkZXByZWNhdGVkT3ZlcnJpZGluZ3NyABN4c2J0aS5hcGkuU2luZ2xldG9u/Kdf+M9W5EYCAAFMAARwYXRodAAQTHhzYnRpL2FwaS9QYXRoO3hxAH4ANnNyAA54c2J0aS5hcGkuUGF0aJs9XAjOpSeEAgABWwAKY29tcG9uZW50c3QAGltMeHNidGkvYXBpL1BhdGhDb21wb25lbnQ7eHB1cgAaW0x4c2J0aS5hcGkuUGF0aENvbXBvbmVudDtD2gl0LWcWdAIAAHhwAAAAAnNyAAx4c2J0aS5hcGkuSWSYMmyLN1PEQAIAAUwAAmlkcQB+ABx4cgAXeHNidGkuYXBpLlBhdGhDb21wb25lbnRfmiJbLoafvAIAAHhwdAAFc2NhbGFzcgAOeHNidGkuYXBpLlRoaXPbCe2mzFpAXAIAAHhxAH4AW3NxAH4AIwB0AARtYWludXEAfgAmAAAAAHNxAH4ATnQABFVuaXRxAH4AVHVyABpbTHhzYnRpLmFwaS5QYXJhbWV0ZXJMaXN0O/XTOh3ys3DuAgAAeHAAAAABc3IAF3hzYnRpLmFwaS5QYXJhbWV0ZXJMaXN01sW8HGRJdOMCAAJaAAppc0ltcGxpY2l0WwAKcGFyYW1ldGVyc3QAHFtMeHNidGkvYXBpL01ldGhvZFBhcmFtZXRlcjt4cAB1cgAcW0x4c2J0aS5hcGkuTWV0aG9kUGFyYW1ldGVyO8+4xV2l3bVtAgAAeHAAAAABc3IAGXhzYnRpLmFwaS5NZXRob2RQYXJhbWV0ZXIfRa4X00mw6gIABFoACmhhc0RlZmF1bHRMAAhtb2RpZmllcnQAHUx4c2J0aS9hcGkvUGFyYW1ldGVyTW9kaWZpZXI7TAAEbmFtZXEAfgAcTAADdHBlcQB+AEF4cAB+cgAbeHNidGkuYXBpLlBhcmFtZXRlck1vZGlmaWVyAAAAAAAAAAASAAB4cQB+ACl0AAVQbGFpbnQABGFyZ3NzcgAXeHNidGkuYXBpLlBhcmFtZXRlcml6ZWQWbO5pA8m7fwIAAkwACGJhc2VUeXBlcQB+AE9bAA10eXBlQXJndW1lbnRzdAARW0x4c2J0aS9hcGkvVHlwZTt4cQB+ADZzcQB+AE50AAVBcnJheXEAfgBUdXIAEVtMeHNidGkuYXBpLlR5cGU7dP+lWnv56UECAAB4cAAAAAFzcQB+AE50AAZTdHJpbmdzcQB+AFJzcQB+AFV1cQB+AFgAAAADc3EAfgBadAAEamF2YXNxAH4AWnQABGxhbmdxAH4AX3BzcQB+ADABdXEAfgB4AAAABHNxAH4ATnQAA0FwcHEAfgBUc3EAfgBOdAALRGVsYXllZEluaXRxAH4AVHNxAH4ATnQABk9iamVjdHEAfgB8c3EAfgBOdAADQW55cQB+AFRwcHVyABRbTHhzYnRpLmFwaS5QYWNrYWdlO1sTGTdwpyehAgAAeHAAAAAAc3IAFXhzYnRpLmFwaS5Db21waWxhdGlvbu364MNq6KBCAgACSgAJc3RhcnRUaW1lWwAHb3V0cHV0c3QAGltMeHNidGkvYXBpL091dHB1dFNldHRpbmc7eHAAAAFVMHW8R3VyABpbTHhzYnRpLmFwaS5PdXRwdXRTZXR0aW5nO39qwvOnh6VCAgAAeHAAAAACc3IAF3hzYnRpLmFwaS5PdXRwdXRTZXR0aW5netmaR3T7HXsCAAJMAA9vdXRwdXREaXJlY3RvcnlxAH4AHEwAD3NvdXJjZURpcmVjdG9yeXEAfgAceHB0ADRDOlxkZXZlbG9wXGdpdFx0dXRvcmlhbHNcZ2F0bGluZ1x0YXJnZXRcdGVzdC1jbGFzc2VzdAAvQzpcZGV2ZWxvcFxnaXRcdHV0b3JpYWxzXGdhdGxpbmdcc3JjXHRlc3Rcc2NhbGFzcQB+AJR0ADRDOlxkZXZlbG9wXGdpdFx0dXRvcmlhbHNcZ2F0bGluZ1x0YXJnZXRcdGVzdC1jbGFzc2VzdAAzQzpcZGV2ZWxvcFxnaXRcdHV0b3JpYWxzXGdhdGxpbmdcc3JjXHRlc3RccmVzb3VyY2VzdXIAAltCrPMX+AYIVOACAAB4cAAAABQuzrLEqIioZtAfdfIVqVHka14RXQ== +C:\develop\git\tutorials\gatling\src\test\scala\IDEPathHelper.scala -> +rO0ABXNyABB4c2J0aS5hcGkuU291cmNlFlpwRASfbtoCAAZJAAdhcGlIYXNoWgAIaGFzTWFjcm9MABhfaW50ZXJuYWxPbmx5X25hbWVIYXNoZXN0ACRMeHNidGkvYXBpL19pbnRlcm5hbE9ubHlfTmFtZUhhc2hlcztMAANhcGl0ABVMeHNidGkvYXBpL1NvdXJjZUFQSTtMAAtjb21waWxhdGlvbnQAF0x4c2J0aS9hcGkvQ29tcGlsYXRpb247WwAEaGFzaHQAAltCeHCXMg60AHNyACJ4c2J0aS5hcGkuX2ludGVybmFsT25seV9OYW1lSGFzaGVzVNq+mfrU7EwCAAJbAA9pbXBsaWNpdE1lbWJlcnN0ACNbTHhzYnRpL2FwaS9faW50ZXJuYWxPbmx5X05hbWVIYXNoO1sADnJlZ3VsYXJNZW1iZXJzcQB+AAd4cHVyACNbTHhzYnRpLmFwaS5faW50ZXJuYWxPbmx5X05hbWVIYXNoO0lagLbdlov0AgAAeHAAAAAAdXEAfgAJAAAAAHNyABN4c2J0aS5hcGkuU291cmNlQVBJuV6n+SkjOKQCAAJbAAtkZWZpbml0aW9uc3QAF1tMeHNidGkvYXBpL0RlZmluaXRpb247WwAIcGFja2FnZXN0ABRbTHhzYnRpL2FwaS9QYWNrYWdlO3hwdXIAF1tMeHNidGkuYXBpLkRlZmluaXRpb247iMlc57TjXg4CAAB4cAAAAAFzcgATeHNidGkuYXBpLkNsYXNzTGlrZYM0HKHfsJdsAgAETAAOZGVmaW5pdGlvblR5cGV0ABpMeHNidGkvYXBpL0RlZmluaXRpb25UeXBlO1sAEHNhdmVkQW5ub3RhdGlvbnN0ABNbTGphdmEvbGFuZy9TdHJpbmc7TAAIc2VsZlR5cGV0ABBMeHNidGkvYXBpL0xhenk7TAAJc3RydWN0dXJlcQB+ABV4cgAheHNidGkuYXBpLlBhcmFtZXRlcml6ZWREZWZpbml0aW9u+RFusdVQPOICAAFbAA50eXBlUGFyYW1ldGVyc3QAGltMeHNidGkvYXBpL1R5cGVQYXJhbWV0ZXI7eHIAFHhzYnRpLmFwaS5EZWZpbml0aW9uhyob6HFC40YCAARMAAZhY2Nlc3N0ABJMeHNidGkvYXBpL0FjY2VzcztbAAthbm5vdGF0aW9uc3QAF1tMeHNidGkvYXBpL0Fubm90YXRpb247TAAJbW9kaWZpZXJzdAAVTHhzYnRpL2FwaS9Nb2RpZmllcnM7TAAEbmFtZXQAEkxqYXZhL2xhbmcvU3RyaW5nO3hwc3IAEHhzYnRpLmFwaS5QdWJsaWO6WD2ubC1gQgIAAHhyABB4c2J0aS5hcGkuQWNjZXNz3WKa+B1jMUgCAAB4cHVyABdbTHhzYnRpLmFwaS5Bbm5vdGF0aW9uO+uX6xkQ9o1IAgAAeHAAAAAAc3IAE3hzYnRpLmFwaS5Nb2RpZmllcnPHERMhaZzcJAIAAUIABWZsYWdzeHAAdAANSURFUGF0aEhlbHBlcnVyABpbTHhzYnRpLmFwaS5UeXBlUGFyYW1ldGVyO9ltJg8onfK2AgAAeHAAAAAAfnIAGHhzYnRpLmFwaS5EZWZpbml0aW9uVHlwZQAAAAAAAAAAEgAAeHIADmphdmEubGFuZy5FbnVtAAAAAAAAAAASAAB4cHQABk1vZHVsZXVyABNbTGphdmEubGFuZy5TdHJpbmc7rdJW5+kde0cCAAB4cAAAAABzcgATeHNidGkuU2FmZUxhenkkSW1wbDuRTxH0RUzJAgADWgAIYml0bWFwJDBMAAJfdHQAEkxqYXZhL2xhbmcvT2JqZWN0O0wABGV2YWx0ABFMc2NhbGEvRnVuY3Rpb24wO3hyABZ4c2J0aS5hcGkuQWJzdHJhY3RMYXp503e1AV+756ACAAB4cAFzcgATeHNidGkuYXBpLkVtcHR5VHlwZbz9nkZJO4kkAgAAeHIAFHhzYnRpLmFwaS5TaW1wbGVUeXBlcnhiiCEjv0ACAAB4cgAOeHNidGkuYXBpLlR5cGU/atkhFkmqygIAAHhwcHNxAH4ALgFzcgATeHNidGkuYXBpLlN0cnVjdHVyZamq+YCTb9gAAgADTAAIZGVjbGFyZWRxAH4AFUwACWluaGVyaXRlZHEAfgAVTAAHcGFyZW50c3EAfgAVeHEAfgA1c3EAfgAuAXVxAH4AEAAAAABwc3EAfgAuAXVxAH4AEAAAAABwc3EAfgAuAXVyABFbTHhzYnRpLmFwaS5UeXBlO3T/pVp7+elBAgAAeHAAAAACc3IAFHhzYnRpLmFwaS5Qcm9qZWN0aW9u89KNVOlFpC0CAAJMAAJpZHEAfgAcTAAGcHJlZml4dAAWTHhzYnRpL2FwaS9TaW1wbGVUeXBlO3hxAH4ANHQABk9iamVjdHNyABN4c2J0aS5hcGkuU2luZ2xldG9u/Kdf+M9W5EYCAAFMAARwYXRodAAQTHhzYnRpL2FwaS9QYXRoO3hxAH4ANHNyAA54c2J0aS5hcGkuUGF0aJs9XAjOpSeEAgABWwAKY29tcG9uZW50c3QAGltMeHNidGkvYXBpL1BhdGhDb21wb25lbnQ7eHB1cgAaW0x4c2J0aS5hcGkuUGF0aENvbXBvbmVudDtD2gl0LWcWdAIAAHhwAAAAA3NyAAx4c2J0aS5hcGkuSWSYMmyLN1PEQAIAAUwAAmlkcQB+ABx4cgAXeHNidGkuYXBpLlBhdGhDb21wb25lbnRfmiJbLoafvAIAAHhwdAAEamF2YXNxAH4ATXQABGxhbmdzcgAOeHNidGkuYXBpLlRoaXPbCe2mzFpAXAIAAHhxAH4ATnNxAH4AQXQAA0FueXNxAH4ARXNxAH4ASHVxAH4ASwAAAAJzcQB+AE10AAVzY2FsYXEAfgBUcHB1cgAUW0x4c2J0aS5hcGkuUGFja2FnZTtbExk3cKcnoQIAAHhwAAAAAHNyABV4c2J0aS5hcGkuQ29tcGlsYXRpb27t+uDDauigQgIAAkoACXN0YXJ0VGltZVsAB291dHB1dHN0ABpbTHhzYnRpL2FwaS9PdXRwdXRTZXR0aW5nO3hwAAABVTB1vEd1cgAaW0x4c2J0aS5hcGkuT3V0cHV0U2V0dGluZzt/asLzp4elQgIAAHhwAAAAAnNyABd4c2J0aS5hcGkuT3V0cHV0U2V0dGluZ3rZmkd0+x17AgACTAAPb3V0cHV0RGlyZWN0b3J5cQB+ABxMAA9zb3VyY2VEaXJlY3RvcnlxAH4AHHhwdAA0QzpcZGV2ZWxvcFxnaXRcdHV0b3JpYWxzXGdhdGxpbmdcdGFyZ2V0XHRlc3QtY2xhc3Nlc3QAL0M6XGRldmVsb3BcZ2l0XHR1dG9yaWFsc1xnYXRsaW5nXHNyY1x0ZXN0XHNjYWxhc3EAfgBjdAA0QzpcZGV2ZWxvcFxnaXRcdHV0b3JpYWxzXGdhdGxpbmdcdGFyZ2V0XHRlc3QtY2xhc3Nlc3QAM0M6XGRldmVsb3BcZ2l0XHR1dG9yaWFsc1xnYXRsaW5nXHNyY1x0ZXN0XHJlc291cmNlc3VyAAJbQqzzF/gGCFTgAgAAeHAAAAAUo+YAKtbjg76iy5bsf/siupK1giI= +C:\develop\git\tutorials\gatling\src\test\scala\org\baeldung\RecordedSimulation.scala -> +rO0ABXNyABB4c2J0aS5hcGkuU291cmNlFlpwRASfbtoCAAZJAAdhcGlIYXNoWgAIaGFzTWFjcm9MABhfaW50ZXJuYWxPbmx5X25hbWVIYXNoZXN0ACRMeHNidGkvYXBpL19pbnRlcm5hbE9ubHlfTmFtZUhhc2hlcztMAANhcGl0ABVMeHNidGkvYXBpL1NvdXJjZUFQSTtMAAtjb21waWxhdGlvbnQAF0x4c2J0aS9hcGkvQ29tcGlsYXRpb247WwAEaGFzaHQAAltCeHARTQnpAHNyACJ4c2J0aS5hcGkuX2ludGVybmFsT25seV9OYW1lSGFzaGVzVNq+mfrU7EwCAAJbAA9pbXBsaWNpdE1lbWJlcnN0ACNbTHhzYnRpL2FwaS9faW50ZXJuYWxPbmx5X05hbWVIYXNoO1sADnJlZ3VsYXJNZW1iZXJzcQB+AAd4cHVyACNbTHhzYnRpLmFwaS5faW50ZXJuYWxPbmx5X05hbWVIYXNoO0lagLbdlov0AgAAeHAAAAAAdXEAfgAJAAAAAHNyABN4c2J0aS5hcGkuU291cmNlQVBJuV6n+SkjOKQCAAJbAAtkZWZpbml0aW9uc3QAF1tMeHNidGkvYXBpL0RlZmluaXRpb247WwAIcGFja2FnZXN0ABRbTHhzYnRpL2FwaS9QYWNrYWdlO3hwdXIAF1tMeHNidGkuYXBpLkRlZmluaXRpb247iMlc57TjXg4CAAB4cAAAAAFzcgATeHNidGkuYXBpLkNsYXNzTGlrZYM0HKHfsJdsAgAETAAOZGVmaW5pdGlvblR5cGV0ABpMeHNidGkvYXBpL0RlZmluaXRpb25UeXBlO1sAEHNhdmVkQW5ub3RhdGlvbnN0ABNbTGphdmEvbGFuZy9TdHJpbmc7TAAIc2VsZlR5cGV0ABBMeHNidGkvYXBpL0xhenk7TAAJc3RydWN0dXJlcQB+ABV4cgAheHNidGkuYXBpLlBhcmFtZXRlcml6ZWREZWZpbml0aW9u+RFusdVQPOICAAFbAA50eXBlUGFyYW1ldGVyc3QAGltMeHNidGkvYXBpL1R5cGVQYXJhbWV0ZXI7eHIAFHhzYnRpLmFwaS5EZWZpbml0aW9uhyob6HFC40YCAARMAAZhY2Nlc3N0ABJMeHNidGkvYXBpL0FjY2VzcztbAAthbm5vdGF0aW9uc3QAF1tMeHNidGkvYXBpL0Fubm90YXRpb247TAAJbW9kaWZpZXJzdAAVTHhzYnRpL2FwaS9Nb2RpZmllcnM7TAAEbmFtZXQAEkxqYXZhL2xhbmcvU3RyaW5nO3hwc3IAEHhzYnRpLmFwaS5QdWJsaWO6WD2ubC1gQgIAAHhyABB4c2J0aS5hcGkuQWNjZXNz3WKa+B1jMUgCAAB4cHVyABdbTHhzYnRpLmFwaS5Bbm5vdGF0aW9uO+uX6xkQ9o1IAgAAeHAAAAAAc3IAE3hzYnRpLmFwaS5Nb2RpZmllcnPHERMhaZzcJAIAAUIABWZsYWdzeHAAdAAfb3JnLmJhZWxkdW5nLlJlY29yZGVkU2ltdWxhdGlvbnVyABpbTHhzYnRpLmFwaS5UeXBlUGFyYW1ldGVyO9ltJg8onfK2AgAAeHAAAAAAfnIAGHhzYnRpLmFwaS5EZWZpbml0aW9uVHlwZQAAAAAAAAAAEgAAeHIADmphdmEubGFuZy5FbnVtAAAAAAAAAAASAAB4cHQACENsYXNzRGVmdXIAE1tMamF2YS5sYW5nLlN0cmluZzut0lbn6R17RwIAAHhwAAAAAHNyABN4c2J0aS5TYWZlTGF6eSRJbXBsO5FPEfRFTMkCAANaAAhiaXRtYXAkMEwAAl90dAASTGphdmEvbGFuZy9PYmplY3Q7TAAEZXZhbHQAEUxzY2FsYS9GdW5jdGlvbjA7eHIAFnhzYnRpLmFwaS5BYnN0cmFjdExhennTd7UBX7vnoAIAAHhwAXNyABN4c2J0aS5hcGkuRW1wdHlUeXBlvP2eRkk7iSQCAAB4cgAUeHNidGkuYXBpLlNpbXBsZVR5cGVyeGKIISO/QAIAAHhyAA54c2J0aS5hcGkuVHlwZT9q2SEWSarKAgAAeHBwc3EAfgAuAXNyABN4c2J0aS5hcGkuU3RydWN0dXJlqar5gJNv2AACAANMAAhkZWNsYXJlZHEAfgAVTAAJaW5oZXJpdGVkcQB+ABVMAAdwYXJlbnRzcQB+ABV4cQB+ADVzcQB+AC4BdXEAfgAQAAAAAHBzcQB+AC4BdXEAfgAQAAAAAHBzcQB+AC4BdXIAEVtMeHNidGkuYXBpLlR5cGU7dP+lWnv56UECAAB4cAAAAANzcgAUeHNidGkuYXBpLlByb2plY3Rpb27z0o1U6UWkLQIAAkwAAmlkcQB+ABxMAAZwcmVmaXh0ABZMeHNidGkvYXBpL1NpbXBsZVR5cGU7eHEAfgA0dAAKU2ltdWxhdGlvbnNyABN4c2J0aS5hcGkuU2luZ2xldG9u/Kdf+M9W5EYCAAFMAARwYXRodAAQTHhzYnRpL2FwaS9QYXRoO3hxAH4ANHNyAA54c2J0aS5hcGkuUGF0aJs9XAjOpSeEAgABWwAKY29tcG9uZW50c3QAGltMeHNidGkvYXBpL1BhdGhDb21wb25lbnQ7eHB1cgAaW0x4c2J0aS5hcGkuUGF0aENvbXBvbmVudDtD2gl0LWcWdAIAAHhwAAAABXNyAAx4c2J0aS5hcGkuSWSYMmyLN1PEQAIAAUwAAmlkcQB+ABx4cgAXeHNidGkuYXBpLlBhdGhDb21wb25lbnRfmiJbLoafvAIAAHhwdAACaW9zcQB+AE10AAdnYXRsaW5nc3EAfgBNdAAEY29yZXNxAH4ATXQACHNjZW5hcmlvc3IADnhzYnRpLmFwaS5UaGlz2wntpsxaQFwCAAB4cQB+AE5zcQB+AEF0AAZPYmplY3RzcQB+AEVzcQB+AEh1cQB+AEsAAAADc3EAfgBNdAAEamF2YXNxAH4ATXQABGxhbmdxAH4AWHNxAH4AQXQAA0FueXNxAH4ARXNxAH4ASHVxAH4ASwAAAAJzcQB+AE10AAVzY2FsYXEAfgBYcHB1cgAUW0x4c2J0aS5hcGkuUGFja2FnZTtbExk3cKcnoQIAAHhwAAAAAnNyABF4c2J0aS5hcGkuUGFja2FnZX5Zj/auzjlYAgABTAAEbmFtZXEAfgAceHB0AAxvcmcuYmFlbGR1bmdzcQB+AGt0AANvcmdzcgAVeHNidGkuYXBpLkNvbXBpbGF0aW9u7frgw2rooEICAAJKAAlzdGFydFRpbWVbAAdvdXRwdXRzdAAaW0x4c2J0aS9hcGkvT3V0cHV0U2V0dGluZzt4cAAAAVUwdbxHdXIAGltMeHNidGkuYXBpLk91dHB1dFNldHRpbmc7f2rC86eHpUICAAB4cAAAAAJzcgAXeHNidGkuYXBpLk91dHB1dFNldHRpbmd62ZpHdPsdewIAAkwAD291dHB1dERpcmVjdG9yeXEAfgAcTAAPc291cmNlRGlyZWN0b3J5cQB+ABx4cHQANEM6XGRldmVsb3BcZ2l0XHR1dG9yaWFsc1xnYXRsaW5nXHRhcmdldFx0ZXN0LWNsYXNzZXN0AC9DOlxkZXZlbG9wXGdpdFx0dXRvcmlhbHNcZ2F0bGluZ1xzcmNcdGVzdFxzY2FsYXNxAH4AdXQANEM6XGRldmVsb3BcZ2l0XHR1dG9yaWFsc1xnYXRsaW5nXHRhcmdldFx0ZXN0LWNsYXNzZXN0ADNDOlxkZXZlbG9wXGdpdFx0dXRvcmlhbHNcZ2F0bGluZ1xzcmNcdGVzdFxyZXNvdXJjZXN1cgACW0Ks8xf4BghU4AIAAHhwAAAAFGvBBRh/5rBKw9Od+I7VHxlVZVNi +C:\develop\git\tutorials\gatling\src\test\scala\Recorder.scala -> +rO0ABXNyABB4c2J0aS5hcGkuU291cmNlFlpwRASfbtoCAAZJAAdhcGlIYXNoWgAIaGFzTWFjcm9MABhfaW50ZXJuYWxPbmx5X25hbWVIYXNoZXN0ACRMeHNidGkvYXBpL19pbnRlcm5hbE9ubHlfTmFtZUhhc2hlcztMAANhcGl0ABVMeHNidGkvYXBpL1NvdXJjZUFQSTtMAAtjb21waWxhdGlvbnQAF0x4c2J0aS9hcGkvQ29tcGlsYXRpb247WwAEaGFzaHQAAltCeHD3nMHWAHNyACJ4c2J0aS5hcGkuX2ludGVybmFsT25seV9OYW1lSGFzaGVzVNq+mfrU7EwCAAJbAA9pbXBsaWNpdE1lbWJlcnN0ACNbTHhzYnRpL2FwaS9faW50ZXJuYWxPbmx5X05hbWVIYXNoO1sADnJlZ3VsYXJNZW1iZXJzcQB+AAd4cHVyACNbTHhzYnRpLmFwaS5faW50ZXJuYWxPbmx5X05hbWVIYXNoO0lagLbdlov0AgAAeHAAAAAAdXEAfgAJAAAAAHNyABN4c2J0aS5hcGkuU291cmNlQVBJuV6n+SkjOKQCAAJbAAtkZWZpbml0aW9uc3QAF1tMeHNidGkvYXBpL0RlZmluaXRpb247WwAIcGFja2FnZXN0ABRbTHhzYnRpL2FwaS9QYWNrYWdlO3hwdXIAF1tMeHNidGkuYXBpLkRlZmluaXRpb247iMlc57TjXg4CAAB4cAAAAAFzcgATeHNidGkuYXBpLkNsYXNzTGlrZYM0HKHfsJdsAgAETAAOZGVmaW5pdGlvblR5cGV0ABpMeHNidGkvYXBpL0RlZmluaXRpb25UeXBlO1sAEHNhdmVkQW5ub3RhdGlvbnN0ABNbTGphdmEvbGFuZy9TdHJpbmc7TAAIc2VsZlR5cGV0ABBMeHNidGkvYXBpL0xhenk7TAAJc3RydWN0dXJlcQB+ABV4cgAheHNidGkuYXBpLlBhcmFtZXRlcml6ZWREZWZpbml0aW9u+RFusdVQPOICAAFbAA50eXBlUGFyYW1ldGVyc3QAGltMeHNidGkvYXBpL1R5cGVQYXJhbWV0ZXI7eHIAFHhzYnRpLmFwaS5EZWZpbml0aW9uhyob6HFC40YCAARMAAZhY2Nlc3N0ABJMeHNidGkvYXBpL0FjY2VzcztbAAthbm5vdGF0aW9uc3QAF1tMeHNidGkvYXBpL0Fubm90YXRpb247TAAJbW9kaWZpZXJzdAAVTHhzYnRpL2FwaS9Nb2RpZmllcnM7TAAEbmFtZXQAEkxqYXZhL2xhbmcvU3RyaW5nO3hwc3IAEHhzYnRpLmFwaS5QdWJsaWO6WD2ubC1gQgIAAHhyABB4c2J0aS5hcGkuQWNjZXNz3WKa+B1jMUgCAAB4cHVyABdbTHhzYnRpLmFwaS5Bbm5vdGF0aW9uO+uX6xkQ9o1IAgAAeHAAAAAAc3IAE3hzYnRpLmFwaS5Nb2RpZmllcnPHERMhaZzcJAIAAUIABWZsYWdzeHAAdAAIUmVjb3JkZXJ1cgAaW0x4c2J0aS5hcGkuVHlwZVBhcmFtZXRlcjvZbSYPKJ3ytgIAAHhwAAAAAH5yABh4c2J0aS5hcGkuRGVmaW5pdGlvblR5cGUAAAAAAAAAABIAAHhyAA5qYXZhLmxhbmcuRW51bQAAAAAAAAAAEgAAeHB0AAZNb2R1bGV1cgATW0xqYXZhLmxhbmcuU3RyaW5nO63SVufpHXtHAgAAeHAAAAACdAAQc2NhbGEuZGVwcmVjYXRlZHQAGnNjYWxhLmRlcHJlY2F0ZWRPdmVycmlkaW5nc3IAE3hzYnRpLlNhZmVMYXp5JEltcGw7kU8R9EVMyQIAA1oACGJpdG1hcCQwTAACX3R0ABJMamF2YS9sYW5nL09iamVjdDtMAARldmFsdAARTHNjYWxhL0Z1bmN0aW9uMDt4cgAWeHNidGkuYXBpLkFic3RyYWN0TGF6edN3tQFfu+egAgAAeHABc3IAE3hzYnRpLmFwaS5FbXB0eVR5cGW8/Z5GSTuJJAIAAHhyABR4c2J0aS5hcGkuU2ltcGxlVHlwZXJ4YoghI79AAgAAeHIADnhzYnRpLmFwaS5UeXBlP2rZIRZJqsoCAAB4cHBzcQB+ADABc3IAE3hzYnRpLmFwaS5TdHJ1Y3R1cmWpqvmAk2/YAAIAA0wACGRlY2xhcmVkcQB+ABVMAAlpbmhlcml0ZWRxAH4AFUwAB3BhcmVudHNxAH4AFXhxAH4AN3NxAH4AMAF1cQB+ABAAAAAAcHNxAH4AMAF1cQB+ABAAAAABc3IADXhzYnRpLmFwaS5EZWZSvp/ifLQ2aQIAAkwACnJldHVyblR5cGV0ABBMeHNidGkvYXBpL1R5cGU7WwAPdmFsdWVQYXJhbWV0ZXJzdAAaW0x4c2J0aS9hcGkvUGFyYW1ldGVyTGlzdDt4cQB+ABZxAH4AIHVxAH4AIQAAAAFzcgAUeHNidGkuYXBpLkFubm90YXRpb27eDoGi9lwKsgIAAlsACWFyZ3VtZW50c3QAH1tMeHNidGkvYXBpL0Fubm90YXRpb25Bcmd1bWVudDtMAARiYXNlcQB+AEF4cHVyAB9bTHhzYnRpLmFwaS5Bbm5vdGF0aW9uQXJndW1lbnQ7UZ2mjzglD3gCAAB4cAAAAAFzcgAceHNidGkuYXBpLkFubm90YXRpb25Bcmd1bWVudNZFsdgDGxd8AgACTAAEbmFtZXEAfgAcTAAFdmFsdWVxAH4AHHhwdAAAdAAqKCJtYWluIHNob3VsZCBub3QgYmUgb3ZlcnJpZGRlbiIsIjIuMTEuMCIpc3IAFHhzYnRpLmFwaS5Qcm9qZWN0aW9u89KNVOlFpC0CAAJMAAJpZHEAfgAcTAAGcHJlZml4dAAWTHhzYnRpL2FwaS9TaW1wbGVUeXBlO3hxAH4ANnQAFGRlcHJlY2F0ZWRPdmVycmlkaW5nc3IAE3hzYnRpLmFwaS5TaW5nbGV0b278p1/4z1bkRgIAAUwABHBhdGh0ABBMeHNidGkvYXBpL1BhdGg7eHEAfgA2c3IADnhzYnRpLmFwaS5QYXRomz1cCM6lJ4QCAAFbAApjb21wb25lbnRzdAAaW0x4c2J0aS9hcGkvUGF0aENvbXBvbmVudDt4cHVyABpbTHhzYnRpLmFwaS5QYXRoQ29tcG9uZW50O0PaCXQtZxZ0AgAAeHAAAAACc3IADHhzYnRpLmFwaS5JZJgybIs3U8RAAgABTAACaWRxAH4AHHhyABd4c2J0aS5hcGkuUGF0aENvbXBvbmVudF+aIlsuhp+8AgAAeHB0AAVzY2FsYXNyAA54c2J0aS5hcGkuVGhpc9sJ7abMWkBcAgAAeHEAfgBbc3EAfgAjAHQABG1haW51cQB+ACYAAAAAc3EAfgBOdAAEVW5pdHEAfgBUdXIAGltMeHNidGkuYXBpLlBhcmFtZXRlckxpc3Q79dM6HfKzcO4CAAB4cAAAAAFzcgAXeHNidGkuYXBpLlBhcmFtZXRlckxpc3TWxbwcZEl04wIAAloACmlzSW1wbGljaXRbAApwYXJhbWV0ZXJzdAAcW0x4c2J0aS9hcGkvTWV0aG9kUGFyYW1ldGVyO3hwAHVyABxbTHhzYnRpLmFwaS5NZXRob2RQYXJhbWV0ZXI7z7jFXaXdtW0CAAB4cAAAAAFzcgAZeHNidGkuYXBpLk1ldGhvZFBhcmFtZXRlch9FrhfTSbDqAgAEWgAKaGFzRGVmYXVsdEwACG1vZGlmaWVydAAdTHhzYnRpL2FwaS9QYXJhbWV0ZXJNb2RpZmllcjtMAARuYW1lcQB+ABxMAAN0cGVxAH4AQXhwAH5yABt4c2J0aS5hcGkuUGFyYW1ldGVyTW9kaWZpZXIAAAAAAAAAABIAAHhxAH4AKXQABVBsYWludAAEYXJnc3NyABd4c2J0aS5hcGkuUGFyYW1ldGVyaXplZBZs7mkDybt/AgACTAAIYmFzZVR5cGVxAH4AT1sADXR5cGVBcmd1bWVudHN0ABFbTHhzYnRpL2FwaS9UeXBlO3hxAH4ANnNxAH4ATnQABUFycmF5cQB+AFR1cgARW0x4c2J0aS5hcGkuVHlwZTt0/6Vae/npQQIAAHhwAAAAAXNxAH4ATnQABlN0cmluZ3NxAH4AUnNxAH4AVXVxAH4AWAAAAANzcQB+AFp0AARqYXZhc3EAfgBadAAEbGFuZ3EAfgBfcHNxAH4AMAF1cQB+AHgAAAAEc3EAfgBOdAADQXBwcQB+AFRzcQB+AE50AAtEZWxheWVkSW5pdHEAfgBUc3EAfgBOdAAGT2JqZWN0cQB+AHxzcQB+AE50AANBbnlxAH4AVHBwdXIAFFtMeHNidGkuYXBpLlBhY2thZ2U7WxMZN3CnJ6ECAAB4cAAAAABzcgAVeHNidGkuYXBpLkNvbXBpbGF0aW9u7frgw2rooEICAAJKAAlzdGFydFRpbWVbAAdvdXRwdXRzdAAaW0x4c2J0aS9hcGkvT3V0cHV0U2V0dGluZzt4cAAAAVUwdbxHdXIAGltMeHNidGkuYXBpLk91dHB1dFNldHRpbmc7f2rC86eHpUICAAB4cAAAAAJzcgAXeHNidGkuYXBpLk91dHB1dFNldHRpbmd62ZpHdPsdewIAAkwAD291dHB1dERpcmVjdG9yeXEAfgAcTAAPc291cmNlRGlyZWN0b3J5cQB+ABx4cHQANEM6XGRldmVsb3BcZ2l0XHR1dG9yaWFsc1xnYXRsaW5nXHRhcmdldFx0ZXN0LWNsYXNzZXN0AC9DOlxkZXZlbG9wXGdpdFx0dXRvcmlhbHNcZ2F0bGluZ1xzcmNcdGVzdFxzY2FsYXNxAH4AlHQANEM6XGRldmVsb3BcZ2l0XHR1dG9yaWFsc1xnYXRsaW5nXHRhcmdldFx0ZXN0LWNsYXNzZXN0ADNDOlxkZXZlbG9wXGdpdFx0dXRvcmlhbHNcZ2F0bGluZ1xzcmNcdGVzdFxyZXNvdXJjZXN1cgACW0Ks8xf4BghU4AIAAHhwAAAAFPT60Ze8DnffBawfUNP6fy8E+yiN +external apis: +0 items +source infos: +4 items +C:\develop\git\tutorials\gatling\src\test\scala\Engine.scala -> +AAAAAAAAAAA= +C:\develop\git\tutorials\gatling\src\test\scala\IDEPathHelper.scala -> +AAAAAAAAAAA= +C:\develop\git\tutorials\gatling\src\test\scala\org\baeldung\RecordedSimulation.scala -> +AAAAAAAAAAA= +C:\develop\git\tutorials\gatling\src\test\scala\Recorder.scala -> +AAAAAAAAAAA= +compilations: +4 items +0 -> rO0ABXNyABV4c2J0aS5hcGkuQ29tcGlsYXRpb27t+uDDauigQgIAAkoACXN0YXJ0VGltZVsAB291dHB1dHN0ABpbTHhzYnRpL2FwaS9PdXRwdXRTZXR0aW5nO3hwAAABVTBzw0J1cgAaW0x4c2J0aS5hcGkuT3V0cHV0U2V0dGluZzt/asLzp4elQgIAAHhwAAAAAnNyABd4c2J0aS5hcGkuT3V0cHV0U2V0dGluZ3rZmkd0+x17AgACTAAPb3V0cHV0RGlyZWN0b3J5dAASTGphdmEvbGFuZy9TdHJpbmc7TAAPc291cmNlRGlyZWN0b3J5cQB+AAZ4cHQANEM6XGRldmVsb3BcZ2l0XHR1dG9yaWFsc1xnYXRsaW5nXHRhcmdldFx0ZXN0LWNsYXNzZXN0AC9DOlxkZXZlbG9wXGdpdFx0dXRvcmlhbHNcZ2F0bGluZ1xzcmNcdGVzdFxzY2FsYXNxAH4ABXQANEM6XGRldmVsb3BcZ2l0XHR1dG9yaWFsc1xnYXRsaW5nXHRhcmdldFx0ZXN0LWNsYXNzZXN0ADNDOlxkZXZlbG9wXGdpdFx0dXRvcmlhbHNcZ2F0bGluZ1xzcmNcdGVzdFxyZXNvdXJjZXM= +1 -> rO0ABXNyABV4c2J0aS5hcGkuQ29tcGlsYXRpb27t+uDDauigQgIAAkoACXN0YXJ0VGltZVsAB291dHB1dHN0ABpbTHhzYnRpL2FwaS9PdXRwdXRTZXR0aW5nO3hwAAABVTBz8ix1cgAaW0x4c2J0aS5hcGkuT3V0cHV0U2V0dGluZzt/asLzp4elQgIAAHhwAAAAAnNyABd4c2J0aS5hcGkuT3V0cHV0U2V0dGluZ3rZmkd0+x17AgACTAAPb3V0cHV0RGlyZWN0b3J5dAASTGphdmEvbGFuZy9TdHJpbmc7TAAPc291cmNlRGlyZWN0b3J5cQB+AAZ4cHQANEM6XGRldmVsb3BcZ2l0XHR1dG9yaWFsc1xnYXRsaW5nXHRhcmdldFx0ZXN0LWNsYXNzZXN0AC9DOlxkZXZlbG9wXGdpdFx0dXRvcmlhbHNcZ2F0bGluZ1xzcmNcdGVzdFxzY2FsYXNxAH4ABXQANEM6XGRldmVsb3BcZ2l0XHR1dG9yaWFsc1xnYXRsaW5nXHRhcmdldFx0ZXN0LWNsYXNzZXN0ADNDOlxkZXZlbG9wXGdpdFx0dXRvcmlhbHNcZ2F0bGluZ1xzcmNcdGVzdFxyZXNvdXJjZXM= +2 -> rO0ABXNyABV4c2J0aS5hcGkuQ29tcGlsYXRpb27t+uDDauigQgIAAkoACXN0YXJ0VGltZVsAB291dHB1dHN0ABpbTHhzYnRpL2FwaS9PdXRwdXRTZXR0aW5nO3hwAAABVTB0hal1cgAaW0x4c2J0aS5hcGkuT3V0cHV0U2V0dGluZzt/asLzp4elQgIAAHhwAAAAAnNyABd4c2J0aS5hcGkuT3V0cHV0U2V0dGluZ3rZmkd0+x17AgACTAAPb3V0cHV0RGlyZWN0b3J5dAASTGphdmEvbGFuZy9TdHJpbmc7TAAPc291cmNlRGlyZWN0b3J5cQB+AAZ4cHQANEM6XGRldmVsb3BcZ2l0XHR1dG9yaWFsc1xnYXRsaW5nXHRhcmdldFx0ZXN0LWNsYXNzZXN0AC9DOlxkZXZlbG9wXGdpdFx0dXRvcmlhbHNcZ2F0bGluZ1xzcmNcdGVzdFxzY2FsYXNxAH4ABXQANEM6XGRldmVsb3BcZ2l0XHR1dG9yaWFsc1xnYXRsaW5nXHRhcmdldFx0ZXN0LWNsYXNzZXN0ADNDOlxkZXZlbG9wXGdpdFx0dXRvcmlhbHNcZ2F0bGluZ1xzcmNcdGVzdFxyZXNvdXJjZXM= +3 -> rO0ABXNyABV4c2J0aS5hcGkuQ29tcGlsYXRpb27t+uDDauigQgIAAkoACXN0YXJ0VGltZVsAB291dHB1dHN0ABpbTHhzYnRpL2FwaS9PdXRwdXRTZXR0aW5nO3hwAAABVTB1vEd1cgAaW0x4c2J0aS5hcGkuT3V0cHV0U2V0dGluZzt/asLzp4elQgIAAHhwAAAAAnNyABd4c2J0aS5hcGkuT3V0cHV0U2V0dGluZ3rZmkd0+x17AgACTAAPb3V0cHV0RGlyZWN0b3J5dAASTGphdmEvbGFuZy9TdHJpbmc7TAAPc291cmNlRGlyZWN0b3J5cQB+AAZ4cHQANEM6XGRldmVsb3BcZ2l0XHR1dG9yaWFsc1xnYXRsaW5nXHRhcmdldFx0ZXN0LWNsYXNzZXN0AC9DOlxkZXZlbG9wXGdpdFx0dXRvcmlhbHNcZ2F0bGluZ1xzcmNcdGVzdFxzY2FsYXNxAH4ABXQANEM6XGRldmVsb3BcZ2l0XHR1dG9yaWFsc1xnYXRsaW5nXHRhcmdldFx0ZXN0LWNsYXNzZXN0ADNDOlxkZXZlbG9wXGdpdFx0dXRvcmlhbHNcZ2F0bGluZ1xzcmNcdGVzdFxyZXNvdXJjZXM= diff --git a/gatling/.classpath b/gatling/.classpath new file mode 100644 index 0000000000..92fb998075 --- /dev/null +++ b/gatling/.classpath @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gatling/.project b/gatling/.project new file mode 100644 index 0000000000..69864064ad --- /dev/null +++ b/gatling/.project @@ -0,0 +1,24 @@ + + + gatling + + + + + + org.eclipse.m2e.core.maven2Builder + + + + + org.scala-ide.sdt.core.scalabuilder + + + + + + org.scala-ide.sdt.core.scalanature + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + From 9f21a102c44b9e236972f86e43476c19ef975e28 Mon Sep 17 00:00:00 2001 From: Ivan Paolillo Date: Tue, 21 Jun 2016 18:13:48 +0200 Subject: [PATCH 014/269] Add JSON Schema validation --- json/.classpath | 32 ----------------- json/.project | 23 ------------ spring-mvc-xml/.classpath | 74 +++++++++++++++++++-------------------- 3 files changed, 37 insertions(+), 92 deletions(-) delete mode 100644 json/.classpath delete mode 100644 json/.project diff --git a/json/.classpath b/json/.classpath deleted file mode 100644 index 4f9b9b5af7..0000000000 --- a/json/.classpath +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/json/.project b/json/.project deleted file mode 100644 index 8424469786..0000000000 --- a/json/.project +++ /dev/null @@ -1,23 +0,0 @@ - - - json - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - - diff --git a/spring-mvc-xml/.classpath b/spring-mvc-xml/.classpath index 6b533711d3..a642d37ceb 100644 --- a/spring-mvc-xml/.classpath +++ b/spring-mvc-xml/.classpath @@ -1,37 +1,37 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 8f35636ba4c5e5619cac52ea042571f11f59e9d0 Mon Sep 17 00:00:00 2001 From: bhaskey Date: Wed, 22 Jun 2016 16:29:32 +0530 Subject: [PATCH 015/269] webjars demo project added webjars directory added to tutorial-master. project is added as webjarsdemo inside that --- .../.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 49502 bytes .../.mvn/wrapper/maven-wrapper.properties | 1 + webjars/webjarsdemo/mvnw | 233 ++++++++++++++++++ webjars/webjarsdemo/mvnw.cmd | 145 +++++++++++ webjars/webjarsdemo/pom.xml | 63 +++++ .../java/com/baeldung/TestController.java | 15 ++ .../com/baeldung/WebjarsdemoApplication.java | 12 + .../src/main/resources/application.properties | 0 .../src/main/resources/templates/index.html | 19 ++ .../baeldung/WebjarsdemoApplicationTests.java | 18 ++ 10 files changed, 506 insertions(+) create mode 100644 webjars/webjarsdemo/.mvn/wrapper/maven-wrapper.jar create mode 100644 webjars/webjarsdemo/.mvn/wrapper/maven-wrapper.properties create mode 100644 webjars/webjarsdemo/mvnw create mode 100644 webjars/webjarsdemo/mvnw.cmd create mode 100644 webjars/webjarsdemo/pom.xml create mode 100644 webjars/webjarsdemo/src/main/java/com/baeldung/TestController.java create mode 100644 webjars/webjarsdemo/src/main/java/com/baeldung/WebjarsdemoApplication.java create mode 100644 webjars/webjarsdemo/src/main/resources/application.properties create mode 100644 webjars/webjarsdemo/src/main/resources/templates/index.html create mode 100644 webjars/webjarsdemo/src/test/java/com/baeldung/WebjarsdemoApplicationTests.java diff --git a/webjars/webjarsdemo/.mvn/wrapper/maven-wrapper.jar b/webjars/webjarsdemo/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..5fd4d5023f1463b5ba3970e33c460c1eb26d748d GIT binary patch literal 49502 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%0A$pwhjXzyA0ZzErH{1@M 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 OJOEd-=rxTO#Qy`$*1Hh^ literal 0 HcmV?d00001 diff --git a/webjars/webjarsdemo/.mvn/wrapper/maven-wrapper.properties b/webjars/webjarsdemo/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000000..eb91947648 --- /dev/null +++ b/webjars/webjarsdemo/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip \ No newline at end of file diff --git a/webjars/webjarsdemo/mvnw b/webjars/webjarsdemo/mvnw new file mode 100644 index 0000000000..a1ba1bf554 --- /dev/null +++ b/webjars/webjarsdemo/mvnw @@ -0,0 +1,233 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # + # Look for the Apple JDKs first to preserve the existing behaviour, and then look + # for the new JDKs provided by Oracle. + # + if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then + # + # Apple JDKs + # + export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then + # + # Apple JDKs + # + export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then + # + # Oracle JDKs + # + export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then + # + # Apple JDKs + # + export JAVA_HOME=`/usr/libexec/java_home` + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Migwn, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + local basedir=$(pwd) + local wdir=$(pwd) + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + wdir=$(cd "$wdir/.."; pwd) + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} "$@" diff --git a/webjars/webjarsdemo/mvnw.cmd b/webjars/webjarsdemo/mvnw.cmd new file mode 100644 index 0000000000..2b934e89dd --- /dev/null +++ b/webjars/webjarsdemo/mvnw.cmd @@ -0,0 +1,145 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +set MAVEN_CMD_LINE_ARGS=%* + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% \ No newline at end of file diff --git a/webjars/webjarsdemo/pom.xml b/webjars/webjarsdemo/pom.xml new file mode 100644 index 0000000000..80e4f0a42a --- /dev/null +++ b/webjars/webjarsdemo/pom.xml @@ -0,0 +1,63 @@ + + + 4.0.0 + + com.baeldung + webjarsdemo + 0.0.1-SNAPSHOT + jar + + webjarsdemo + Demo project for webjars using Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 1.3.5.RELEASE + + + + + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.webjars + bootstrap + 3.3.4 + + + org.webjars + jquery + 2.1.4 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/webjars/webjarsdemo/src/main/java/com/baeldung/TestController.java b/webjars/webjarsdemo/src/main/java/com/baeldung/TestController.java new file mode 100644 index 0000000000..19a1c18c6b --- /dev/null +++ b/webjars/webjarsdemo/src/main/java/com/baeldung/TestController.java @@ -0,0 +1,15 @@ +package com.baeldung; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class TestController { + + @RequestMapping(value="/") + public String welcome(Model model){ + return "index"; + } + +} diff --git a/webjars/webjarsdemo/src/main/java/com/baeldung/WebjarsdemoApplication.java b/webjars/webjarsdemo/src/main/java/com/baeldung/WebjarsdemoApplication.java new file mode 100644 index 0000000000..c14dc682af --- /dev/null +++ b/webjars/webjarsdemo/src/main/java/com/baeldung/WebjarsdemoApplication.java @@ -0,0 +1,12 @@ +package com.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class WebjarsdemoApplication { + + public static void main(String[] args) { + SpringApplication.run(WebjarsdemoApplication.class, args); + } +} diff --git a/webjars/webjarsdemo/src/main/resources/application.properties b/webjars/webjarsdemo/src/main/resources/application.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/webjars/webjarsdemo/src/main/resources/templates/index.html b/webjars/webjarsdemo/src/main/resources/templates/index.html new file mode 100644 index 0000000000..046d21600a --- /dev/null +++ b/webjars/webjarsdemo/src/main/resources/templates/index.html @@ -0,0 +1,19 @@ + + + WebJars Demo + + + + +

+
+ × + Success! It is working as we expected. +
+
+ + + + + + \ No newline at end of file diff --git a/webjars/webjarsdemo/src/test/java/com/baeldung/WebjarsdemoApplicationTests.java b/webjars/webjarsdemo/src/test/java/com/baeldung/WebjarsdemoApplicationTests.java new file mode 100644 index 0000000000..284cda5d31 --- /dev/null +++ b/webjars/webjarsdemo/src/test/java/com/baeldung/WebjarsdemoApplicationTests.java @@ -0,0 +1,18 @@ +package com.baeldung; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = WebjarsdemoApplication.class) +@WebAppConfiguration +public class WebjarsdemoApplicationTests { + + @Test + public void contextLoads() { + } + +} From 23c7c7d84455836d3221765174e8386ba3ebeff6 Mon Sep 17 00:00:00 2001 From: Guillermo Casanova Date: Thu, 23 Jun 2016 02:26:55 +0200 Subject: [PATCH 016/269] New redis module We have created this module to work with Redis Java libraries Jedis tested so far --- pom.xml | 1 + redis/pom.xml | 41 ++++ .../src/test/java/com/baeldung/JedisTest.java | 225 ++++++++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 redis/pom.xml create mode 100644 redis/src/test/java/com/baeldung/JedisTest.java diff --git a/pom.xml b/pom.xml index f16861cc68..00967e2c35 100644 --- a/pom.xml +++ b/pom.xml @@ -71,6 +71,7 @@ xml lombok + redis diff --git a/redis/pom.xml b/redis/pom.xml new file mode 100644 index 0000000000..98775b7e13 --- /dev/null +++ b/redis/pom.xml @@ -0,0 +1,41 @@ + + + + 4.0.0 + com.baeldung + redis + 0.1-SNAPSHOT + + redis + http://maven.apache.org + + + + redis.clients + jedis + 2.8.1 + + + + com.github.kstyrc + embedded-redis + 0.6 + + + + junit + junit + ${junit.version} + test + + + + + UTF-8 + + + 4.12 + + diff --git a/redis/src/test/java/com/baeldung/JedisTest.java b/redis/src/test/java/com/baeldung/JedisTest.java new file mode 100644 index 0000000000..cba99a1e73 --- /dev/null +++ b/redis/src/test/java/com/baeldung/JedisTest.java @@ -0,0 +1,225 @@ +package com.baeldung; + +import java.io.IOException; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.JedisPoolConfig; +import redis.clients.jedis.Pipeline; +import redis.clients.jedis.Response; +import redis.clients.jedis.Transaction; +import redis.embedded.RedisServer; + +/** + * Unit test for Redis Java library - Jedis. + */ +public class JedisTest { + + private Jedis jedis; + private static RedisServer redisServer; + + public JedisTest() { + jedis = new Jedis(); + } + + @BeforeClass + public static void setUp() throws IOException { + redisServer = new RedisServer(6379); + redisServer.start(); + } + + @AfterClass + public static void destroy() { + redisServer.stop(); + } + + @After + public void flush() { + jedis.flushAll(); + } + + @Test + public void givenAStringThenSaveItAsRedisStrings() { + String key = "key"; + String value = "value"; + + jedis.set(key, value); + String value2 = jedis.get(key); + + Assert.assertEquals(value, value2); + } + + @Test + public void givenListElementsThenSaveThemInRedisList() { + String queue = "queue#tasks"; + + String taskOne = "firstTask"; + String taskTwo = "secondTask"; + String taskThree = "thirdTask"; + + jedis.lpush(queue, taskOne, taskTwo); + + String taskReturnedOne = jedis.rpop(queue); + + jedis.lpush(queue, taskThree); + Assert.assertEquals(taskOne, taskReturnedOne); + + String taskReturnedTwo = jedis.rpop(queue); + String taskReturnedThree = jedis.rpop(queue); + + Assert.assertEquals(taskTwo, taskReturnedTwo); + Assert.assertEquals(taskThree, taskReturnedThree); + + String taskReturnedFour = jedis.rpop(queue); + Assert.assertNull(taskReturnedFour); + } + + @Test + public void givenSetElementsThenSaveThemInRedisSet() { + String countries = "countries"; + + String countryOne = "Spain"; + String countryTwo = "Ireland"; + String countryThree = "Ireland"; + + jedis.sadd(countries, countryOne); + + Set countriesSet = jedis.smembers(countries); + Assert.assertEquals(1, countriesSet.size()); + + jedis.sadd(countries, countryTwo); + countriesSet = jedis.smembers(countries); + Assert.assertEquals(2, countriesSet.size()); + + jedis.sadd(countries, countryThree); + countriesSet = jedis.smembers(countries); + Assert.assertEquals(2, countriesSet.size()); + + boolean exists = jedis.sismember(countries, countryThree); + Assert.assertTrue(exists); + } + + @Test + public void givenObjectFieldsThenSaveThemInRedisHash() { + String key = "user#1"; + + String field = "name"; + String value = "William"; + + String field2 = "job"; + String value2 = "politician"; + + jedis.hset(key, field, value); + jedis.hset(key, field2, value2); + + String value3 = jedis.hget(key, field); + Assert.assertEquals(value, value3); + + Map fields = jedis.hgetAll(key); + String value4 = fields.get(field2); + Assert.assertEquals(value2, value4); + } + + @Test + public void givenARankingThenSaveItInRedisSortedSet() { + String key = "ranking"; + + Map scores = new HashMap<>(); + + scores.put("PlayerOne", 3000.0); + scores.put("PlayerTwo", 1500.0); + scores.put("PlayerThree", 8200.0); + + for (String player : scores.keySet()) { + jedis.zadd(key, scores.get(player), player); + } + + Set players = jedis.zrevrange(key, 0, 1); + Assert.assertEquals("PlayerThree", players.iterator().next()); + + long rank = jedis.zrevrank(key, "PlayerOne"); + Assert.assertEquals(1, rank); + } + + @Test + public void givenMultipleOperationsThatNeedToBeExecutedAtomicallyThenWrapThemInATransaction() { + String friendsPrefix = "friends#"; + + String userOneId = "4352523"; + String userTwoId = "5552321"; + + Transaction t = jedis.multi(); + t.sadd(friendsPrefix + userOneId, userTwoId); + t.sadd(friendsPrefix + userTwoId, userOneId); + t.exec(); + + boolean exists = jedis.sismember(friendsPrefix + userOneId, userTwoId); + Assert.assertTrue(exists); + + exists = jedis.sismember(friendsPrefix + userTwoId, userOneId); + Assert.assertTrue(exists); + } + + @Test + public void givenMultipleIndependentOperationsWhenNetworkOptimizationIsImportantThenWrapThemInAPipeline() { + String userOneId = "4352523"; + String userTwoId = "4849888"; + + Pipeline p = jedis.pipelined(); + p.sadd("searched#" + userOneId, "paris"); + p.zadd("ranking", 126, userOneId); + p.zadd("ranking", 325, userTwoId); + Response pipeExists = p.sismember("searched#" + userOneId, "paris"); + Response> pipeRanking = p.zrange("ranking", 0, -1); + p.sync(); + + Assert.assertTrue(pipeExists.get()); + Assert.assertEquals(2, pipeRanking.get().size()); + } + + @Test + public void givenAPoolConfigurationThenCreateAJedisPool() { + final JedisPoolConfig poolConfig = buildPoolConfig(); + + try (JedisPool jedisPool = new JedisPool(poolConfig, "localhost"); + Jedis jedis = jedisPool.getResource()) { + + // do simple operation to verify that the Jedis resource is working properly + String key = "key"; + String value = "value"; + + jedis.set(key, value); + String value2 = jedis.get(key); + + Assert.assertEquals(value, value2); + + // flush Redis + jedis.flushAll(); + } + } + + private JedisPoolConfig buildPoolConfig() { + final JedisPoolConfig poolConfig = new JedisPoolConfig(); + poolConfig.setMaxTotal(128); + poolConfig.setMaxIdle(128); + poolConfig.setMinIdle(16); + poolConfig.setTestOnBorrow(true); + poolConfig.setTestOnReturn(true); + poolConfig.setTestWhileIdle(true); + poolConfig.setMinEvictableIdleTimeMillis(Duration.ofSeconds(60).toMillis()); + poolConfig.setTimeBetweenEvictionRunsMillis(Duration.ofSeconds(30).toMillis()); + poolConfig.setNumTestsPerEvictionRun(3); + poolConfig.setBlockWhenExhausted(true); + return poolConfig; + } +} From 19ba450c086de761e31e6991a3c6c80d2b77d418 Mon Sep 17 00:00:00 2001 From: Micah Silverman Date: Fri, 24 Jun 2016 12:14:11 -0400 Subject: [PATCH 017/269] Created jjwt tutorial --- jjwt/.gitignore | 3 + jjwt/pom.xml | 59 ++++++++++++++++++ .../jsonwebtoken/jjwtfun/DemoApplication.java | 12 ++++ .../controller/DynamicJWTController.java | 45 ++++++++++++++ .../controller/FixedJWTController.java | 61 +++++++++++++++++++ .../src/main/resources/application.properties | 0 .../jjwtfun/DemoApplicationTests.java | 18 ++++++ pom.xml | 1 + 8 files changed, 199 insertions(+) create mode 100644 jjwt/.gitignore create mode 100644 jjwt/pom.xml create mode 100644 jjwt/src/main/java/io/jsonwebtoken/jjwtfun/DemoApplication.java create mode 100644 jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java create mode 100644 jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FixedJWTController.java create mode 100644 jjwt/src/main/resources/application.properties create mode 100644 jjwt/src/test/java/io/jsonwebtoken/jjwtfun/DemoApplicationTests.java diff --git a/jjwt/.gitignore b/jjwt/.gitignore new file mode 100644 index 0000000000..f83e8cf07c --- /dev/null +++ b/jjwt/.gitignore @@ -0,0 +1,3 @@ +.idea +target +*.iml diff --git a/jjwt/pom.xml b/jjwt/pom.xml new file mode 100644 index 0000000000..0764194803 --- /dev/null +++ b/jjwt/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + + io.jsonwebtoken + jjwtfun + 0.0.1-SNAPSHOT + jar + + jjwtfun + Exercising the JJWT + + + org.springframework.boot + spring-boot-starter-parent + 1.3.5.RELEASE + + + + + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-devtools + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.springframework.boot + spring-boot-starter-test + test + + + + io.jsonwebtoken + jjwt + 0.6.0 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/DemoApplication.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/DemoApplication.java new file mode 100644 index 0000000000..2d09c182b6 --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/DemoApplication.java @@ -0,0 +1,12 @@ +package io.jsonwebtoken.jjwtfun; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DemoApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java new file mode 100644 index 0000000000..e1d98bb199 --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java @@ -0,0 +1,45 @@ +package io.jsonwebtoken.jjwtfun.controller; + +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.io.UnsupportedEncodingException; +import java.util.AbstractMap.SimpleEntry; +import java.util.Collections; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@RestController +public class DynamicJWTController { + @Value("#{ @environment['jjwtfun.secret'] ?: 'secret' }") + String secret; + + Map map = Collections.unmodifiableMap(Stream.of( + new SimpleEntry<>("iss", ""), + new SimpleEntry<>("a", ""), + new SimpleEntry<>("b", ""), + new SimpleEntry<>("c", ""), + new SimpleEntry<>("d", ""), + new SimpleEntry<>("e", ""), + new SimpleEntry<>("f", ""), + new SimpleEntry<>("g", ""), + new SimpleEntry<>("h", "")) + .collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue()))); + + @RequestMapping(value = "/dynamic-builder", method = RequestMethod.POST) + public String dynamicBuilder(@RequestBody Map claims) throws UnsupportedEncodingException { + return Jwts.builder() + .setClaims(claims) + .signWith( + SignatureAlgorithm.HS256, + secret.getBytes("UTF-8") + ) + .compact(); + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FixedJWTController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FixedJWTController.java new file mode 100644 index 0000000000..7a648063ac --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FixedJWTController.java @@ -0,0 +1,61 @@ +package io.jsonwebtoken.jjwtfun.controller; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.MalformedJwtException; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.SignatureException; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import java.io.UnsupportedEncodingException; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +@RestController +public class FixedJWTController { + + @RequestMapping("/fixed-builder") + public String fixedBuilder() throws UnsupportedEncodingException { + + String jws = Jwts.builder() + .setSubject("msilverman") + .setExpiration(Date.from(Instant.now().plus(1, ChronoUnit.DAYS))) + .claim("name", "Micah Silverman") + .claim("scope", "admins") + .signWith( + SignatureAlgorithm.HS256, + "secret".getBytes("UTF-8") + ) + .compact(); + + return jws; + } + + @RequestMapping("/fixed-parser") + public Jws fixedParser(@RequestParam String jws) throws UnsupportedEncodingException { + Jws claims = Jwts.parser() + .setSigningKey("secret".getBytes("UTF-8")) + .parseClaimsJws(jws); + + return claims; + } + + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler({SignatureException.class, MalformedJwtException.class}) + public Map exception(Exception e) { + Map response = new HashMap<>(); + response.put("status", "ERROR"); + response.put("message", e.getMessage()); + response.put("exception-type", e.getClass().getName()); + return response; + } +} diff --git a/jjwt/src/main/resources/application.properties b/jjwt/src/main/resources/application.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/jjwt/src/test/java/io/jsonwebtoken/jjwtfun/DemoApplicationTests.java b/jjwt/src/test/java/io/jsonwebtoken/jjwtfun/DemoApplicationTests.java new file mode 100644 index 0000000000..7e5b9b78f1 --- /dev/null +++ b/jjwt/src/test/java/io/jsonwebtoken/jjwtfun/DemoApplicationTests.java @@ -0,0 +1,18 @@ +package io.jsonwebtoken.jjwtfun; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = DemoApplication.class) +@WebAppConfiguration +public class DemoApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/pom.xml b/pom.xml index 75281ce80d..9e1d7e44c2 100644 --- a/pom.xml +++ b/pom.xml @@ -22,6 +22,7 @@ httpclient jackson javaxval + jjwt jooq-spring json-path mockito From bf9c5b3c917a261d0f026932acb8e6ee4240480b Mon Sep 17 00:00:00 2001 From: Micah Silverman Date: Fri, 24 Jun 2016 14:53:14 -0400 Subject: [PATCH 018/269] Added HomeController with usage. Updated static and dynamic jwt builders. --- ...plication.java => JJWTFunApplication.java} | 4 +- .../controller/DynamicJWTController.java | 63 +++++++++++++------ .../jjwtfun/controller/HomeController.java | 27 ++++++++ ...ntroller.java => StaticJWTController.java} | 12 ++-- .../jjwtfun/DemoApplicationTests.java | 2 +- 5 files changed, 82 insertions(+), 26 deletions(-) rename jjwt/src/main/java/io/jsonwebtoken/jjwtfun/{DemoApplication.java => JJWTFunApplication.java} (71%) create mode 100644 jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/HomeController.java rename jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/{FixedJWTController.java => StaticJWTController.java} (84%) diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/DemoApplication.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/JJWTFunApplication.java similarity index 71% rename from jjwt/src/main/java/io/jsonwebtoken/jjwtfun/DemoApplication.java rename to jjwt/src/main/java/io/jsonwebtoken/jjwtfun/JJWTFunApplication.java index 2d09c182b6..7189617d55 100644 --- a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/DemoApplication.java +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/JJWTFunApplication.java @@ -4,9 +4,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication -public class DemoApplication { +public class JJWTFunApplication { public static void main(String[] args) { - SpringApplication.run(DemoApplication.class, args); + SpringApplication.run(JJWTFunApplication.class, args); } } diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java index e1d98bb199..fff7e1d6a2 100644 --- a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java @@ -1,39 +1,27 @@ package io.jsonwebtoken.jjwtfun.controller; +import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import java.io.UnsupportedEncodingException; -import java.util.AbstractMap.SimpleEntry; -import java.util.Collections; +import java.time.Instant; +import java.util.Date; import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; + +import static org.springframework.web.bind.annotation.RequestMethod.POST; @RestController public class DynamicJWTController { @Value("#{ @environment['jjwtfun.secret'] ?: 'secret' }") String secret; - Map map = Collections.unmodifiableMap(Stream.of( - new SimpleEntry<>("iss", ""), - new SimpleEntry<>("a", ""), - new SimpleEntry<>("b", ""), - new SimpleEntry<>("c", ""), - new SimpleEntry<>("d", ""), - new SimpleEntry<>("e", ""), - new SimpleEntry<>("f", ""), - new SimpleEntry<>("g", ""), - new SimpleEntry<>("h", "")) - .collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue()))); - - @RequestMapping(value = "/dynamic-builder", method = RequestMethod.POST) - public String dynamicBuilder(@RequestBody Map claims) throws UnsupportedEncodingException { + @RequestMapping(value = "/dynamic-builder-general", method = POST) + public String dynamicBuilderGeneric(@RequestBody Map claims) throws UnsupportedEncodingException { return Jwts.builder() .setClaims(claims) .signWith( @@ -42,4 +30,41 @@ public class DynamicJWTController { ) .compact(); } + + @RequestMapping(value = "/dynamic-builder-specific", method = POST) + public String dynamicBuilderSpecific(@RequestBody Map claims) throws UnsupportedEncodingException { + JwtBuilder builder = Jwts.builder(); + + claims.forEach((key, value) -> { + switch (key) { + case "iss": + builder.setIssuer((String)value); + break; + case "sub": + builder.setSubject((String)value); + break; + case "aud": + builder.setAudience((String)value); + break; + case "exp": + builder.setExpiration(Date.from(Instant.ofEpochSecond(Long.parseLong((String)value)))); + break; + case "nbf": + builder.setNotBefore(Date.from(Instant.ofEpochSecond(Long.parseLong((String)value)))); + break; + case "iat": + builder.setIssuedAt(Date.from(Instant.ofEpochSecond(Long.parseLong((String)value)))); + break; + case "jti": + builder.setId((String)value); + break; + default: + builder.claim(key, value); + } + }); + + builder.signWith(SignatureAlgorithm.HS256, secret.getBytes("UTF-8")); + + return builder.compact(); + } } diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/HomeController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/HomeController.java new file mode 100644 index 0000000000..d6717e383f --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/HomeController.java @@ -0,0 +1,27 @@ +package io.jsonwebtoken.jjwtfun.controller; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; + +@RestController +public class HomeController { + + @RequestMapping("/") + public String home(HttpServletRequest req) { + String requestUrl = getUrl(req); + return "Available commands (assumes httpie - https://github.com/jkbrzt/httpie):\n" + + " http " + requestUrl + "/\n\tThis usage\n" + + " http " + requestUrl + "/static-builder\n\tbuild JWT from hardcoded claims\n" + + " http " + requestUrl + "/dynamic-builder-general claim-1=value-1 ... [claim-n=value-n]\n\tbuild JWT from passed in claims (using general claims map)\n" + + " http " + requestUrl + "/dynamic-builder-specific claim-1=value-1 ... [claim-n=value-n]\n\tbuild JWT from passed in claims (using specific claims methods)\n" + + " http " + requestUrl + "/parser?jwt=\n\tParse passed in JWT\n"; + } + + private String getUrl(HttpServletRequest req) { + return req.getScheme() + "://" + + req.getServerName() + + ((req.getServerPort() == 80 || req.getServerPort() == 443) ? "" : ":" + req.getServerPort()); + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FixedJWTController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java similarity index 84% rename from jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FixedJWTController.java rename to jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java index 7a648063ac..6f98ffcd94 100644 --- a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FixedJWTController.java +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java @@ -9,6 +9,7 @@ import io.jsonwebtoken.SignatureException; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; @@ -20,10 +21,13 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; -@RestController -public class FixedJWTController { +import static org.springframework.web.bind.annotation.RequestMethod.GET; +import static org.springframework.web.bind.annotation.RequestMethod.POST; - @RequestMapping("/fixed-builder") +@RestController +public class StaticJWTController { + + @RequestMapping(value = "/static-builder", method = POST) public String fixedBuilder() throws UnsupportedEncodingException { String jws = Jwts.builder() @@ -40,7 +44,7 @@ public class FixedJWTController { return jws; } - @RequestMapping("/fixed-parser") + @RequestMapping(value = "/parser", method = GET) public Jws fixedParser(@RequestParam String jws) throws UnsupportedEncodingException { Jws claims = Jwts.parser() .setSigningKey("secret".getBytes("UTF-8")) diff --git a/jjwt/src/test/java/io/jsonwebtoken/jjwtfun/DemoApplicationTests.java b/jjwt/src/test/java/io/jsonwebtoken/jjwtfun/DemoApplicationTests.java index 7e5b9b78f1..357d91ed73 100644 --- a/jjwt/src/test/java/io/jsonwebtoken/jjwtfun/DemoApplicationTests.java +++ b/jjwt/src/test/java/io/jsonwebtoken/jjwtfun/DemoApplicationTests.java @@ -7,7 +7,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; @RunWith(SpringJUnit4ClassRunner.class) -@SpringApplicationConfiguration(classes = DemoApplication.class) +@SpringApplicationConfiguration(classes = JJWTFunApplication.class) @WebAppConfiguration public class DemoApplicationTests { From df9e4d7ef5d74b5d76a2daef792450a056dc9651 Mon Sep 17 00:00:00 2001 From: Micah Silverman Date: Sat, 25 Jun 2016 21:11:56 -0400 Subject: [PATCH 019/269] Updated date method calls. --- .../io/jsonwebtoken/jjwtfun/controller/HomeController.java | 2 +- .../jjwtfun/controller/StaticJWTController.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/HomeController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/HomeController.java index d6717e383f..fabc6f1f2a 100644 --- a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/HomeController.java +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/HomeController.java @@ -12,7 +12,7 @@ public class HomeController { public String home(HttpServletRequest req) { String requestUrl = getUrl(req); return "Available commands (assumes httpie - https://github.com/jkbrzt/httpie):\n" + - " http " + requestUrl + "/\n\tThis usage\n" + + " http " + requestUrl + "/\n\tThis usage message\n" + " http " + requestUrl + "/static-builder\n\tbuild JWT from hardcoded claims\n" + " http " + requestUrl + "/dynamic-builder-general claim-1=value-1 ... [claim-n=value-n]\n\tbuild JWT from passed in claims (using general claims map)\n" + " http " + requestUrl + "/dynamic-builder-specific claim-1=value-1 ... [claim-n=value-n]\n\tbuild JWT from passed in claims (using specific claims methods)\n" + diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java index 6f98ffcd94..114900285f 100644 --- a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java @@ -27,14 +27,16 @@ import static org.springframework.web.bind.annotation.RequestMethod.POST; @RestController public class StaticJWTController { - @RequestMapping(value = "/static-builder", method = POST) + @RequestMapping(value = "/static-builder", method = GET) public String fixedBuilder() throws UnsupportedEncodingException { String jws = Jwts.builder() + .setIssuer("Stormpath") .setSubject("msilverman") - .setExpiration(Date.from(Instant.now().plus(1, ChronoUnit.DAYS))) .claim("name", "Micah Silverman") .claim("scope", "admins") + .setIssuedAt(Date.from(Instant.ofEpochSecond(1466796822))) // Fri Jun 24 2016 15:33:42 GMT-0400 (EDT) + .setExpiration(Date.from(Instant.ofEpochSecond(1466883222))) // Sat Jun 25 2016 15:33:42 GMT-0400 (EDT) .signWith( SignatureAlgorithm.HS256, "secret".getBytes("UTF-8") From 330c8680c938e54abf6606b9a9af9db4943c8911 Mon Sep 17 00:00:00 2001 From: Raquel Garrido Date: Sun, 26 Jun 2016 11:55:42 +0200 Subject: [PATCH 020/269] XML libraries support (#463) * dom4j * added more parsers * StaxParser * Jaxb binding * Jaxb binding * Finish article --- xml/pom.xml | 200 ++++++++---------- .../java/com/baeldung/xml/DefaultParser.java | 10 +- .../java/com/baeldung/xml/Dom4JParser.java | 131 ++++++++++++ .../java/com/baeldung/xml/JDomParser.java | 62 ++++++ .../java/com/baeldung/xml/JaxbParser.java | 69 ++++++ .../main/java/com/baeldung/xml/JaxenDemo.java | 57 +++++ .../java/com/baeldung/xml/StaxParser.java | 120 +++++++++++ .../com/baeldung/xml/binding/Tutorial.java | 61 ++++++ .../com/baeldung/xml/binding/Tutorials.java | 23 ++ .../java/com/baeldung/xml/model/Tutorial.java | 49 +++++ .../com/baeldung/xml/DefaultParserTest.java | 11 +- .../com/baeldung/xml/Dom4JParserTest.java | 88 ++++++++ .../java/com/baeldung/xml/JDomParserTest.java | 38 ++++ .../java/com/baeldung/xml/JaxbParserTest.java | 46 ++++ .../java/com/baeldung/xml/JaxenDemoTest.java | 25 +++ .../java/com/baeldung/xml/StaxParserTest.java | 28 +++ xml/src/test/resources/example.xml | 20 +- xml/src/test/resources/example_namespace.xml | 20 +- xml/src/test/resources/example_new.xml | 10 + xml/src/test/resources/example_updated.xml | 32 +++ 20 files changed, 957 insertions(+), 143 deletions(-) create mode 100644 xml/src/main/java/com/baeldung/xml/Dom4JParser.java create mode 100644 xml/src/main/java/com/baeldung/xml/JDomParser.java create mode 100644 xml/src/main/java/com/baeldung/xml/JaxbParser.java create mode 100644 xml/src/main/java/com/baeldung/xml/JaxenDemo.java create mode 100644 xml/src/main/java/com/baeldung/xml/StaxParser.java create mode 100644 xml/src/main/java/com/baeldung/xml/binding/Tutorial.java create mode 100644 xml/src/main/java/com/baeldung/xml/binding/Tutorials.java create mode 100644 xml/src/main/java/com/baeldung/xml/model/Tutorial.java create mode 100644 xml/src/test/java/com/baeldung/xml/Dom4JParserTest.java create mode 100644 xml/src/test/java/com/baeldung/xml/JDomParserTest.java create mode 100644 xml/src/test/java/com/baeldung/xml/JaxbParserTest.java create mode 100644 xml/src/test/java/com/baeldung/xml/JaxenDemoTest.java create mode 100644 xml/src/test/java/com/baeldung/xml/StaxParserTest.java create mode 100644 xml/src/test/resources/example_new.xml create mode 100644 xml/src/test/resources/example_updated.xml diff --git a/xml/pom.xml b/xml/pom.xml index fc158901e6..9d88bd75eb 100644 --- a/xml/pom.xml +++ b/xml/pom.xml @@ -1,139 +1,117 @@ - 4.0.0 - com.baeldung - xml - 0.1-SNAPSHOT + 4.0.0 + com.baeldung + xml + 0.1-SNAPSHOT - xml + xml - - + + + + dom4j + dom4j + 1.6.1 + + + jaxen + jaxen + 1.1.6 + - - com.google.guava - guava - ${guava.version} - - - commons-io - commons-io - 2.4 - + + org.jdom + jdom2 + 2.0.6 + - - org.apache.commons - commons-collections4 - 4.0 - + + xerces + xercesImpl + 2.9.1 + - - org.apache.commons - commons-lang3 - ${commons-lang3.version} - - - - + + + commons-io + commons-io + 2.4 + - - junit - junit - ${junit.version} - test - + + org.apache.commons + commons-collections4 + 4.0 + - - org.hamcrest - hamcrest-core - ${org.hamcrest.version} - test - - - org.hamcrest - hamcrest-library - ${org.hamcrest.version} - test - + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + - - org.mockito - mockito-core - ${mockito.version} - test - - + - - xml - - - src/main/resources - true - - + + junit + junit + ${junit.version} + test + - + - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - 1.8 - 1.8 - - + + xml + + + src/main/resources + true + + - - org.apache.maven.plugins - maven-surefire-plugin - ${maven-surefire-plugin.version} - + - + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + 1.8 + 1.8 + + - + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + - - - 4.3.11.Final - 5.1.38 + - - 2.7.2 + - - 1.7.13 - 1.1.3 + - - 5.1.3.Final + + 19.0 + 3.4 - - 19.0 - 3.4 + + 4.12 - - 1.3 - 4.12 - 1.10.19 + + 3.5.1 + 2.6 + 2.19.1 + 2.7 + 1.4.18 - 4.4.1 - 4.5 - - 2.9.0 - - - 3.5.1 - 2.6 - 2.19.1 - 2.7 - 1.4.18 - - + diff --git a/xml/src/main/java/com/baeldung/xml/DefaultParser.java b/xml/src/main/java/com/baeldung/xml/DefaultParser.java index 89326f45c9..1f2a7418fb 100644 --- a/xml/src/main/java/com/baeldung/xml/DefaultParser.java +++ b/xml/src/main/java/com/baeldung/xml/DefaultParser.java @@ -39,7 +39,7 @@ public class DefaultParser { XPath xPath = XPathFactory.newInstance().newXPath(); - String expression = "/Tutorials/Tutorial"; + String expression = "/tutorials/tutorial"; nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET); @@ -60,7 +60,7 @@ public class DefaultParser { XPath xPath = XPathFactory.newInstance().newXPath(); - String expression = "/Tutorials/Tutorial[@tutId=" + "'" + id + "'" + "]"; + String expression = "/tutorials/tutorial[@tutId=" + "'" + id + "'" + "]"; node = (Node) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODE); @@ -83,7 +83,7 @@ public class DefaultParser { XPath xPath = XPathFactory.newInstance().newXPath(); - String expression = "//Tutorial[descendant::title[text()=" + "'" + name + "'" + "]]"; + String expression = "//tutorial[descendant::title[text()=" + "'" + name + "'" + "]]"; nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET); @@ -107,7 +107,7 @@ public class DefaultParser { XPath xPath = XPathFactory.newInstance().newXPath(); - String expression = "//Tutorial[number(translate(date, '/', '')) > " + date + "]"; + String expression = "//tutorial[number(translate(date, '/', '')) > " + date + "]"; nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET); @@ -151,7 +151,7 @@ public class DefaultParser { } }); - String expression = "/bdn:Tutorials/bdn:Tutorial"; + String expression = "/bdn:tutorials/bdn:tutorial"; nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET); diff --git a/xml/src/main/java/com/baeldung/xml/Dom4JParser.java b/xml/src/main/java/com/baeldung/xml/Dom4JParser.java new file mode 100644 index 0000000000..d9058ba236 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xml/Dom4JParser.java @@ -0,0 +1,131 @@ +package com.baeldung.xml; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Iterator; +import java.util.List; + +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.DocumentHelper; +import org.dom4j.Element; +import org.dom4j.Node; +import org.dom4j.io.OutputFormat; +import org.dom4j.io.SAXReader; +import org.dom4j.io.XMLWriter; + +public class Dom4JParser { + + private File file; + + public Dom4JParser(File file) { + this.file = file; + } + + public Element getRootElement() { + try { + SAXReader reader = new SAXReader(); + Document document = reader.read(file); + return document.getRootElement(); + } catch (DocumentException e) { + e.printStackTrace(); + return null; + } + } + + public List getFirstElementList() { + try { + SAXReader reader = new SAXReader(); + Document document = reader.read(file); + return document.getRootElement().elements(); + } catch (DocumentException e) { + e.printStackTrace(); + return null; + } + } + + public Node getNodeById(String id) { + try { + SAXReader reader = new SAXReader(); + Document document = reader.read(file); + List elements = document.selectNodes("//*[@tutId='" + id + "']"); + return elements.get(0); + } catch (DocumentException e) { + e.printStackTrace(); + return null; + } + } + + public Node getElementsListByTitle(String name) { + try { + SAXReader reader = new SAXReader(); + Document document = reader.read(file); + List elements = document + .selectNodes("//tutorial[descendant::title[text()=" + "'" + name + "'" + "]]"); + return elements.get(0); + } catch (DocumentException e) { + e.printStackTrace(); + return null; + } + } + + public void generateModifiedDocument() { + try { + SAXReader reader = new SAXReader(); + Document document = reader.read(file); + List nodes = document.selectNodes("/tutorials/tutorial"); + for (Node node : nodes) { + Element element = (Element) node; + Iterator iterator = element.elementIterator("title"); + while (iterator.hasNext()) { + Element title = (Element) iterator.next(); + title.setText(title.getText() + " updated"); + } + } + XMLWriter writer = new XMLWriter(new FileWriter(new File("src/test/resources/example_updated.xml"))); + writer.write(document); + writer.close(); + } catch (DocumentException e) { + e.printStackTrace(); + + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public void generateNewDocument() { + try { + Document document = DocumentHelper.createDocument(); + Element root = document.addElement("XMLTutorials"); + Element tutorialElement = root.addElement("tutorial").addAttribute("tutId", "01"); + tutorialElement.addAttribute("type", "xml"); + + tutorialElement.addElement("title").addText("XML with Dom4J"); + + tutorialElement.addElement("description").addText("XML handling with Dom4J"); + + tutorialElement.addElement("date").addText("14/06/2016"); + + tutorialElement.addElement("author").addText("Dom4J tech writer"); + + OutputFormat format = OutputFormat.createPrettyPrint(); + XMLWriter writer = new XMLWriter(new FileWriter(new File("src/test/resources/example_new.xml")), format); + writer.write(document); + writer.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public File getFile() { + return file; + } + + public void setFile(File file) { + this.file = file; + } + +} diff --git a/xml/src/main/java/com/baeldung/xml/JDomParser.java b/xml/src/main/java/com/baeldung/xml/JDomParser.java new file mode 100644 index 0000000000..08676b44f8 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xml/JDomParser.java @@ -0,0 +1,62 @@ +package com.baeldung.xml; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import org.jdom2.Document; +import org.jdom2.Element; +import org.jdom2.JDOMException; +import org.jdom2.filter.Filters; +import org.jdom2.input.SAXBuilder; +import org.jdom2.xpath.XPathExpression; +import org.jdom2.xpath.XPathFactory; + + +public class JDomParser { + + private File file; + + public JDomParser(File file) { + this.file = file; + } + + public List getAllTitles() { + try { + SAXBuilder builder = new SAXBuilder(); + Document doc = builder.build(this.getFile()); + Element tutorials = doc.getRootElement(); + List titles = tutorials.getChildren("tutorial"); + return titles; + } catch (JDOMException | IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } + } + + public Element getNodeById(String id) { + try { + SAXBuilder builder = new SAXBuilder(); + Document document = (Document) builder.build(file); + String filter = "//*[@tutId='" + id + "']"; + XPathFactory xFactory = XPathFactory.instance(); + XPathExpression expr = xFactory.compile(filter, Filters.element()); + List node = expr.evaluate(document); + + return node.get(0); + } catch (JDOMException | IOException e ) { + e.printStackTrace(); + return null; + } + } + + public File getFile() { + return file; + } + + public void setFile(File file) { + this.file = file; + } + +} diff --git a/xml/src/main/java/com/baeldung/xml/JaxbParser.java b/xml/src/main/java/com/baeldung/xml/JaxbParser.java new file mode 100644 index 0000000000..9c06ec5fba --- /dev/null +++ b/xml/src/main/java/com/baeldung/xml/JaxbParser.java @@ -0,0 +1,69 @@ +package com.baeldung.xml; + +import java.io.File; +import java.util.ArrayList; +import java.util.Date; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; + +import com.baeldung.xml.binding.Tutorial; +import com.baeldung.xml.binding.Tutorials; + +public class JaxbParser { + + private File file; + + public JaxbParser(File file) { + this.file = file; + } + + public Tutorials getFullDocument() { + try { + JAXBContext jaxbContext = JAXBContext.newInstance(Tutorials.class); + Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); + Tutorials tutorials = (Tutorials) jaxbUnmarshaller.unmarshal(this.getFile()); + return tutorials; + } catch (JAXBException e) { + e.printStackTrace(); + return null; + } + } + + public void createNewDocument() { + Tutorials tutorials = new Tutorials(); + tutorials.setTutorial(new ArrayList()); + Tutorial tut = new Tutorial(); + tut.setTutId("01"); + tut.setType("XML"); + tut.setTitle("XML with Jaxb"); + tut.setDescription("XML Binding with Jaxb"); + tut.setDate(new Date()); + tut.setAuthor("Jaxb author"); + tutorials.getTutorial().add(tut); + + try { + JAXBContext jaxbContext = JAXBContext.newInstance(Tutorials.class); + Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); + + jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + + jaxbMarshaller.marshal(tutorials, file); + + } catch (JAXBException e) { + e.printStackTrace(); + } + + } + + public File getFile() { + return file; + } + + public void setFile(File file) { + this.file = file; + } + +} diff --git a/xml/src/main/java/com/baeldung/xml/JaxenDemo.java b/xml/src/main/java/com/baeldung/xml/JaxenDemo.java new file mode 100644 index 0000000000..0c2dca0573 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xml/JaxenDemo.java @@ -0,0 +1,57 @@ +package com.baeldung.xml; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.List; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.jaxen.JaxenException; +import org.jaxen.XPath; +import org.jaxen.dom.DOMXPath; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +public class JaxenDemo { + + private File file; + + public JaxenDemo(File file) { + this.file = file; + } + + public List getAllTutorial(){ + try { + FileInputStream fileIS = new FileInputStream(this.getFile()); + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + + Document xmlDocument = builder.parse(fileIS); + + String expression = "/tutorials/tutorial"; + + XPath path = new DOMXPath(expression); + List result = path.selectNodes(xmlDocument); + return result; + + } catch (SAXException | IOException | ParserConfigurationException | JaxenException e) { + e.printStackTrace(); + return null; + } + + } + + public File getFile() { + return file; + } + + public void setFile(File file) { + this.file = file; + } + + +} diff --git a/xml/src/main/java/com/baeldung/xml/StaxParser.java b/xml/src/main/java/com/baeldung/xml/StaxParser.java new file mode 100644 index 0000000000..6f83e022f8 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xml/StaxParser.java @@ -0,0 +1,120 @@ +package com.baeldung.xml; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; + +import com.baeldung.xml.model.Tutorial; + +public class StaxParser { + + private File file; + + public StaxParser(File file) { + this.file = file; + } + + public List getAllTutorial() { + boolean bTitle = false; + boolean bDescription = false; + boolean bDate = false; + boolean bAuthor = false; + List tutorials = new ArrayList(); + try { + XMLInputFactory factory = XMLInputFactory.newInstance(); + XMLEventReader eventReader = factory.createXMLEventReader(new FileReader(this.getFile())); + Tutorial current = null; + while (eventReader.hasNext()) { + XMLEvent event = eventReader.nextEvent(); + switch (event.getEventType()) { + case XMLStreamConstants.START_ELEMENT: + StartElement startElement = event.asStartElement(); + String qName = startElement.getName().getLocalPart(); + if (qName.equalsIgnoreCase("tutorial")) { + current = new Tutorial(); + Iterator attributes = startElement.getAttributes(); + while (attributes.hasNext()) { + Attribute currentAt = attributes.next(); + if (currentAt.getName().toString().equalsIgnoreCase("tutId")) { + current.setTutId(currentAt.getValue()); + } else if (currentAt.getName().toString().equalsIgnoreCase("type")) { + current.setType(currentAt.getValue()); + } + } + } else if (qName.equalsIgnoreCase("title")) { + bTitle = true; + } else if (qName.equalsIgnoreCase("description")) { + bDescription = true; + } else if (qName.equalsIgnoreCase("date")) { + bDate = true; + } else if (qName.equalsIgnoreCase("author")) { + bAuthor = true; + } + break; + case XMLStreamConstants.CHARACTERS: + Characters characters = event.asCharacters(); + if (bTitle) { + if (current != null) { + current.setTitle(characters.getData()); + } + bTitle = false; + } + if (bDescription) { + if (current != null) { + current.setDescription(characters.getData()); + } + bDescription = false; + } + if (bDate) { + if (current != null) { + current.setDate(characters.getData()); + } + bDate = false; + } + if (bAuthor) { + if (current != null) { + current.setAuthor(characters.getData()); + } + bAuthor = false; + } + break; + case XMLStreamConstants.END_ELEMENT: + EndElement endElement = event.asEndElement(); + if (endElement.getName().getLocalPart().equalsIgnoreCase("tutorial")) { + if(current != null){ + tutorials.add(current); + } + } + break; + } + } + + } catch (FileNotFoundException | XMLStreamException e) { + e.printStackTrace(); + } + + return tutorials; + } + + public File getFile() { + return file; + } + + public void setFile(File file) { + this.file = file; + } + +} diff --git a/xml/src/main/java/com/baeldung/xml/binding/Tutorial.java b/xml/src/main/java/com/baeldung/xml/binding/Tutorial.java new file mode 100644 index 0000000000..c4668a9f77 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xml/binding/Tutorial.java @@ -0,0 +1,61 @@ +package com.baeldung.xml.binding; + +import java.util.Date; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; + +public class Tutorial { + + private String tutId; + private String type; + private String title; + private String description; + private Date date; + private String author; + + + public String getTutId() { + return tutId; + } + + @XmlAttribute + public void setTutId(String tutId) { + this.tutId = tutId; + } + public String getType() { + return type; + } + @XmlAttribute + public void setType(String type) { + this.type = type; + } + public String getTitle() { + return title; + } + @XmlElement + public void setTitle(String title) { + this.title = title; + } + public String getDescription() { + return description; + } + @XmlElement + public void setDescription(String description) { + this.description = description; + } + public Date getDate() { + return date; + } + @XmlElement + public void setDate(Date date) { + this.date = date; + } + public String getAuthor() { + return author; + } + @XmlElement + public void setAuthor(String author) { + this.author = author; + } +} diff --git a/xml/src/main/java/com/baeldung/xml/binding/Tutorials.java b/xml/src/main/java/com/baeldung/xml/binding/Tutorials.java new file mode 100644 index 0000000000..ab6669c0ad --- /dev/null +++ b/xml/src/main/java/com/baeldung/xml/binding/Tutorials.java @@ -0,0 +1,23 @@ +package com.baeldung.xml.binding; + +import java.util.List; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +public class Tutorials { + + private List tutorial; + + public List getTutorial() { + return tutorial; + } + + @XmlElement + public void setTutorial(List tutorial) { + this.tutorial = tutorial; + } + + +} diff --git a/xml/src/main/java/com/baeldung/xml/model/Tutorial.java b/xml/src/main/java/com/baeldung/xml/model/Tutorial.java new file mode 100644 index 0000000000..40a3f858cf --- /dev/null +++ b/xml/src/main/java/com/baeldung/xml/model/Tutorial.java @@ -0,0 +1,49 @@ +package com.baeldung.xml.model; + +public class Tutorial { + + private String tutId; + private String type; + private String title; + private String description; + private String date; + private String author; + + + public String getTutId() { + return tutId; + } + public void setTutId(String tutId) { + this.tutId = tutId; + } + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + public String getTitle() { + return title; + } + public void setTitle(String title) { + this.title = title; + } + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + public String getDate() { + return date; + } + public void setDate(String date) { + this.date = date; + } + public String getAuthor() { + return author; + } + public void setAuthor(String author) { + this.author = author; + } +} diff --git a/xml/src/test/java/com/baeldung/xml/DefaultParserTest.java b/xml/src/test/java/com/baeldung/xml/DefaultParserTest.java index 451917a5da..734e7a93cb 100644 --- a/xml/src/test/java/com/baeldung/xml/DefaultParserTest.java +++ b/xml/src/test/java/com/baeldung/xml/DefaultParserTest.java @@ -8,9 +8,6 @@ import org.junit.Test; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -/** - * Unit test for simple App. - */ public class DefaultParserTest { final String fileName = "src/test/resources/example.xml"; @@ -29,7 +26,7 @@ public class DefaultParserTest { } @Test - public void getNodeListByTitle() { + public void getNodeListByTitleTest() { parser = new DefaultParser(new File(fileName)); NodeList list = parser.getNodeListByTitle("XML"); @@ -47,7 +44,7 @@ public class DefaultParserTest { } @Test - public void getNodeById() { + public void getNodeByIdTest() { parser = new DefaultParser(new File(fileName)); Node node = parser.getNodeById("03"); @@ -56,7 +53,7 @@ public class DefaultParserTest { } @Test - public void getNodeListByDate(){ + public void getNodeListByDateTest(){ parser = new DefaultParser(new File(fileName)); NodeList list = parser.getNodeListByTitle("04022016"); for (int i = 0; null != list && i < list.getLength(); i++) { @@ -73,7 +70,7 @@ public class DefaultParserTest { } @Test - public void getNodeListWithNamespace(){ + public void getNodeListWithNamespaceTest(){ parser = new DefaultParser(new File(fileNameSpace)); NodeList list = parser.getAllTutorials(); assertNotNull(list); diff --git a/xml/src/test/java/com/baeldung/xml/Dom4JParserTest.java b/xml/src/test/java/com/baeldung/xml/Dom4JParserTest.java new file mode 100644 index 0000000000..277eca8355 --- /dev/null +++ b/xml/src/test/java/com/baeldung/xml/Dom4JParserTest.java @@ -0,0 +1,88 @@ +package com.baeldung.xml; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.List; + +import org.dom4j.Element; +import org.dom4j.Node; +import org.junit.Test; + +public class Dom4JParserTest { + + final String fileName = "src/test/resources/example.xml"; + + Dom4JParser parser; + + @Test + public void getRootElementTest() { + parser = new Dom4JParser(new File(fileName)); + Element root = parser.getRootElement(); + + assertNotNull(root); + assertTrue(root.elements().size() == 4); + } + + @Test + public void getFirstElementListTest() { + parser = new Dom4JParser(new File(fileName)); + List firstList = parser.getFirstElementList(); + + assertNotNull(firstList); + assertTrue(firstList.size() == 4); + assertTrue(firstList.get(0).attributeValue("type").equals("java")); + } + + @Test + public void getElementByIdTest() { + parser = new Dom4JParser(new File(fileName)); + Node element = parser.getNodeById("03"); + + String type = element.valueOf("@type"); + assertEquals("android", type); + } + + @Test + public void getElementsListByTitleTest() { + parser = new Dom4JParser(new File(fileName)); + Node element = parser.getElementsListByTitle("XML"); + + assertEquals("java", element.valueOf("@type")); + assertEquals("02", element.valueOf("@tutId")); + assertEquals("XML", element.selectSingleNode("title").getText()); + assertEquals("title", element.selectSingleNode("title").getName()); + } + + @Test + public void generateModifiedDocumentTest() { + parser = new Dom4JParser(new File(fileName)); + parser.generateModifiedDocument(); + + File generatedFile = new File("src/test/resources/example_updated.xml"); + assertTrue(generatedFile.exists()); + + parser.setFile(generatedFile); + Node element = parser.getNodeById("02"); + + assertEquals("XML updated", element.selectSingleNode("title").getText()); + + } + + @Test + public void generateNewDocumentTest() { + parser = new Dom4JParser(new File(fileName)); + parser.generateNewDocument(); + + File newFile = new File("src/test/resources/example_new.xml"); + assertTrue(newFile.exists()); + + parser.setFile(newFile); + Node element = parser.getNodeById("01"); + + assertEquals("XML with Dom4J", element.selectSingleNode("title").getText()); + + } +} diff --git a/xml/src/test/java/com/baeldung/xml/JDomParserTest.java b/xml/src/test/java/com/baeldung/xml/JDomParserTest.java new file mode 100644 index 0000000000..981458469f --- /dev/null +++ b/xml/src/test/java/com/baeldung/xml/JDomParserTest.java @@ -0,0 +1,38 @@ +package com.baeldung.xml; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.List; + +import org.jdom2.Element; +import org.junit.Test; + +public class JDomParserTest { + + final String fileName = "src/test/resources/example.xml"; + + JDomParser parser; + + @Test + public void getFirstElementListTest() { + parser = new JDomParser(new File(fileName)); + List firstList = parser.getAllTitles(); + + assertNotNull(firstList); + assertTrue(firstList.size() == 4); + assertTrue(firstList.get(0).getAttributeValue("type").equals("java")); + } + + @Test + public void getElementByIdTest() { + parser = new JDomParser(new File(fileName)); + Element el = parser.getNodeById("03"); + + String type = el.getAttributeValue("type"); + assertEquals("android", type); + } + +} diff --git a/xml/src/test/java/com/baeldung/xml/JaxbParserTest.java b/xml/src/test/java/com/baeldung/xml/JaxbParserTest.java new file mode 100644 index 0000000000..4d6ddf5f65 --- /dev/null +++ b/xml/src/test/java/com/baeldung/xml/JaxbParserTest.java @@ -0,0 +1,46 @@ +package com.baeldung.xml; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; + +import org.dom4j.Node; +import org.junit.Test; + +import com.baeldung.xml.binding.Tutorials; + +public class JaxbParserTest { + + + final String fileName = "src/test/resources/example.xml"; + + JaxbParser parser; + + @Test + public void getFullDocumentTest(){ + parser = new JaxbParser(new File(fileName)); + Tutorials tutorials = parser.getFullDocument(); + + assertNotNull(tutorials); + assertTrue(tutorials.getTutorial().size() == 4); + assertTrue(tutorials.getTutorial().get(0).getType().equalsIgnoreCase("java")); + } + + @Test + public void createNewDocumentTest(){ + File newFile = new File("src/test/resources/example_new.xml"); + parser = new JaxbParser(newFile); + parser.createNewDocument(); + + + assertTrue(newFile.exists()); + + Tutorials tutorials = parser.getFullDocument(); + + assertNotNull(tutorials); + assertTrue(tutorials.getTutorial().size() == 1); + assertTrue(tutorials.getTutorial().get(0).getTitle().equalsIgnoreCase("XML with Jaxb")); + } +} diff --git a/xml/src/test/java/com/baeldung/xml/JaxenDemoTest.java b/xml/src/test/java/com/baeldung/xml/JaxenDemoTest.java new file mode 100644 index 0000000000..2521fcaf8a --- /dev/null +++ b/xml/src/test/java/com/baeldung/xml/JaxenDemoTest.java @@ -0,0 +1,25 @@ +package com.baeldung.xml; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.List; + +import org.junit.Test; + +public class JaxenDemoTest { + + final String fileName = "src/test/resources/example.xml"; + + JaxenDemo jaxenDemo; + + @Test + public void getFirstLevelNodeListTest() { + jaxenDemo = new JaxenDemo(new File(fileName)); + List list = jaxenDemo.getAllTutorial(); + + assertNotNull(list); + assertTrue(list.size() == 4); + } +} diff --git a/xml/src/test/java/com/baeldung/xml/StaxParserTest.java b/xml/src/test/java/com/baeldung/xml/StaxParserTest.java new file mode 100644 index 0000000000..3188777a79 --- /dev/null +++ b/xml/src/test/java/com/baeldung/xml/StaxParserTest.java @@ -0,0 +1,28 @@ +package com.baeldung.xml; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.List; + +import org.junit.Test; + +import com.baeldung.xml.model.Tutorial; + +public class StaxParserTest { + + final String fileName = "src/test/resources/example.xml"; + + StaxParser parser; + + @Test + public void getAllTutorialsTest(){ + parser = new StaxParser(new File(fileName)); + List tutorials = parser.getAllTutorial(); + + assertNotNull(tutorials); + assertTrue(tutorials.size() == 4); + assertTrue(tutorials.get(0).getType().equalsIgnoreCase("java")); + } +} diff --git a/xml/src/test/resources/example.xml b/xml/src/test/resources/example.xml index d546dd137b..0993b6240a 100644 --- a/xml/src/test/resources/example.xml +++ b/xml/src/test/resources/example.xml @@ -1,24 +1,24 @@ - - + + Guava Introduction to Guava 04/04/2016 GuavaAuthor - - + + XML Introduction to XPath 04/05/2016 XMLAuthor - - + + Android Introduction to Android 04/03/2016 AndroidAuthor - - + + Spring Introduction to Spring 04/02/2016 @@ -28,5 +28,5 @@
Spring MVC
Spring Batch
-
-
\ No newline at end of file +
+
\ No newline at end of file diff --git a/xml/src/test/resources/example_namespace.xml b/xml/src/test/resources/example_namespace.xml index 26131302ea..f1a880951a 100644 --- a/xml/src/test/resources/example_namespace.xml +++ b/xml/src/test/resources/example_namespace.xml @@ -1,24 +1,24 @@ - - + + Guava Introduction to Guava 04/04/2016 GuavaAuthor - - + + XML Introduction to XPath 04/05/2016 XMLAuthor - - + + Android Introduction to Android 04/03/2016 AndroidAuthor - - + + Spring Introduction to Spring 04/02/2016 @@ -28,5 +28,5 @@
Spring MVC
Spring Batch
-
-
\ No newline at end of file +
+
\ No newline at end of file diff --git a/xml/src/test/resources/example_new.xml b/xml/src/test/resources/example_new.xml new file mode 100644 index 0000000000..020760fdd3 --- /dev/null +++ b/xml/src/test/resources/example_new.xml @@ -0,0 +1,10 @@ + + + + + XML with Dom4J + XML handling with Dom4J + 14/06/2016 + Dom4J tech writer + + diff --git a/xml/src/test/resources/example_updated.xml b/xml/src/test/resources/example_updated.xml new file mode 100644 index 0000000000..962ca0c889 --- /dev/null +++ b/xml/src/test/resources/example_updated.xml @@ -0,0 +1,32 @@ + + + + Guava updated + Introduction to Guava + 04/04/2016 + GuavaAuthor + + + XML updated + Introduction to XPath + 04/05/2016 + XMLAuthor + + + Android updated + Introduction to Android + 04/03/2016 + AndroidAuthor + + + Spring updated + Introduction to Spring + 04/02/2016 + SpringAuthor + +
Spring Core
+
Spring MVC
+
Spring Batch
+
+
+
\ No newline at end of file From 40ed303abc75817d344c7cd736c828a846c88f74 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sun, 26 Jun 2016 11:59:31 +0200 Subject: [PATCH 021/269] Refactor xml examples --- .../com/baeldung/xml/DefaultParserTest.java | 20 +++++++------ .../com/baeldung/xml/Dom4JParserTest.java | 30 +++++++++---------- .../java/com/baeldung/xml/JDomParserTest.java | 16 +++++----- .../java/com/baeldung/xml/JaxbParserTest.java | 15 ++++------ .../java/com/baeldung/xml/JaxenDemoTest.java | 10 +++---- .../java/com/baeldung/xml/StaxParserTest.java | 13 ++++---- 6 files changed, 51 insertions(+), 53 deletions(-) diff --git a/xml/src/test/java/com/baeldung/xml/DefaultParserTest.java b/xml/src/test/java/com/baeldung/xml/DefaultParserTest.java index 734e7a93cb..7408e41b92 100644 --- a/xml/src/test/java/com/baeldung/xml/DefaultParserTest.java +++ b/xml/src/test/java/com/baeldung/xml/DefaultParserTest.java @@ -1,20 +1,22 @@ package com.baeldung.xml; -import static org.junit.Assert.*; - -import java.io.File; - import org.junit.Test; import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import java.io.File; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + public class DefaultParserTest { - final String fileName = "src/test/resources/example.xml"; + private final String fileName = "src/test/resources/example.xml"; - final String fileNameSpace = "src/test/resources/example_namespace.xml"; + private final String fileNameSpace = "src/test/resources/example_namespace.xml"; - DefaultParser parser; + private DefaultParser parser; @Test public void getFirstLevelNodeListTest() { @@ -30,7 +32,7 @@ public class DefaultParserTest { parser = new DefaultParser(new File(fileName)); NodeList list = parser.getNodeListByTitle("XML"); - for (int i = 0; null != list && i < list.getLength(); i++) { + for (int i = 0; i < list.getLength(); i++) { Node nod = list.item(i); assertEquals("java", nod.getAttributes().getNamedItem("type").getTextContent()); assertEquals("02", nod.getAttributes().getNamedItem("tutId").getTextContent()); @@ -56,7 +58,7 @@ public class DefaultParserTest { public void getNodeListByDateTest(){ parser = new DefaultParser(new File(fileName)); NodeList list = parser.getNodeListByTitle("04022016"); - for (int i = 0; null != list && i < list.getLength(); i++) { + for (int i = 0; i < list.getLength(); i++) { Node nod = list.item(i); assertEquals("java", nod.getAttributes().getNamedItem("type").getTextContent()); assertEquals("04", nod.getAttributes().getNamedItem("tutId").getTextContent()); diff --git a/xml/src/test/java/com/baeldung/xml/Dom4JParserTest.java b/xml/src/test/java/com/baeldung/xml/Dom4JParserTest.java index 277eca8355..77e5fcdcda 100644 --- a/xml/src/test/java/com/baeldung/xml/Dom4JParserTest.java +++ b/xml/src/test/java/com/baeldung/xml/Dom4JParserTest.java @@ -1,25 +1,25 @@ package com.baeldung.xml; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.util.List; - import org.dom4j.Element; import org.dom4j.Node; import org.junit.Test; +import java.io.File; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + public class Dom4JParserTest { - final String fileName = "src/test/resources/example.xml"; + private static final String FILE_NAME = "src/test/resources/example.xml"; - Dom4JParser parser; + private Dom4JParser parser; @Test public void getRootElementTest() { - parser = new Dom4JParser(new File(fileName)); + parser = new Dom4JParser(new File(FILE_NAME)); Element root = parser.getRootElement(); assertNotNull(root); @@ -28,7 +28,7 @@ public class Dom4JParserTest { @Test public void getFirstElementListTest() { - parser = new Dom4JParser(new File(fileName)); + parser = new Dom4JParser(new File(FILE_NAME)); List firstList = parser.getFirstElementList(); assertNotNull(firstList); @@ -38,7 +38,7 @@ public class Dom4JParserTest { @Test public void getElementByIdTest() { - parser = new Dom4JParser(new File(fileName)); + parser = new Dom4JParser(new File(FILE_NAME)); Node element = parser.getNodeById("03"); String type = element.valueOf("@type"); @@ -47,7 +47,7 @@ public class Dom4JParserTest { @Test public void getElementsListByTitleTest() { - parser = new Dom4JParser(new File(fileName)); + parser = new Dom4JParser(new File(FILE_NAME)); Node element = parser.getElementsListByTitle("XML"); assertEquals("java", element.valueOf("@type")); @@ -58,7 +58,7 @@ public class Dom4JParserTest { @Test public void generateModifiedDocumentTest() { - parser = new Dom4JParser(new File(fileName)); + parser = new Dom4JParser(new File(FILE_NAME)); parser.generateModifiedDocument(); File generatedFile = new File("src/test/resources/example_updated.xml"); @@ -73,7 +73,7 @@ public class Dom4JParserTest { @Test public void generateNewDocumentTest() { - parser = new Dom4JParser(new File(fileName)); + parser = new Dom4JParser(new File(FILE_NAME)); parser.generateNewDocument(); File newFile = new File("src/test/resources/example_new.xml"); diff --git a/xml/src/test/java/com/baeldung/xml/JDomParserTest.java b/xml/src/test/java/com/baeldung/xml/JDomParserTest.java index 981458469f..e4034c48f0 100644 --- a/xml/src/test/java/com/baeldung/xml/JDomParserTest.java +++ b/xml/src/test/java/com/baeldung/xml/JDomParserTest.java @@ -1,20 +1,20 @@ package com.baeldung.xml; +import org.jdom2.Element; +import org.junit.Test; + +import java.io.File; +import java.util.List; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import java.io.File; -import java.util.List; - -import org.jdom2.Element; -import org.junit.Test; - public class JDomParserTest { - final String fileName = "src/test/resources/example.xml"; + private final String fileName = "src/test/resources/example.xml"; - JDomParser parser; + private JDomParser parser; @Test public void getFirstElementListTest() { diff --git a/xml/src/test/java/com/baeldung/xml/JaxbParserTest.java b/xml/src/test/java/com/baeldung/xml/JaxbParserTest.java index 4d6ddf5f65..6e1a201b59 100644 --- a/xml/src/test/java/com/baeldung/xml/JaxbParserTest.java +++ b/xml/src/test/java/com/baeldung/xml/JaxbParserTest.java @@ -1,22 +1,19 @@ package com.baeldung.xml; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import com.baeldung.xml.binding.Tutorials; +import org.junit.Test; import java.io.File; -import org.dom4j.Node; -import org.junit.Test; - -import com.baeldung.xml.binding.Tutorials; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; public class JaxbParserTest { - final String fileName = "src/test/resources/example.xml"; + private final String fileName = "src/test/resources/example.xml"; - JaxbParser parser; + private JaxbParser parser; @Test public void getFullDocumentTest(){ diff --git a/xml/src/test/java/com/baeldung/xml/JaxenDemoTest.java b/xml/src/test/java/com/baeldung/xml/JaxenDemoTest.java index 2521fcaf8a..8a88484f11 100644 --- a/xml/src/test/java/com/baeldung/xml/JaxenDemoTest.java +++ b/xml/src/test/java/com/baeldung/xml/JaxenDemoTest.java @@ -1,18 +1,18 @@ package com.baeldung.xml; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import org.junit.Test; import java.io.File; import java.util.List; -import org.junit.Test; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; public class JaxenDemoTest { - final String fileName = "src/test/resources/example.xml"; + private final String fileName = "src/test/resources/example.xml"; - JaxenDemo jaxenDemo; + private JaxenDemo jaxenDemo; @Test public void getFirstLevelNodeListTest() { diff --git a/xml/src/test/java/com/baeldung/xml/StaxParserTest.java b/xml/src/test/java/com/baeldung/xml/StaxParserTest.java index 3188777a79..d1080c88ac 100644 --- a/xml/src/test/java/com/baeldung/xml/StaxParserTest.java +++ b/xml/src/test/java/com/baeldung/xml/StaxParserTest.java @@ -1,20 +1,19 @@ package com.baeldung.xml; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import com.baeldung.xml.model.Tutorial; +import org.junit.Test; import java.io.File; import java.util.List; -import org.junit.Test; - -import com.baeldung.xml.model.Tutorial; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; public class StaxParserTest { - final String fileName = "src/test/resources/example.xml"; + private final String fileName = "src/test/resources/example.xml"; - StaxParser parser; + private StaxParser parser; @Test public void getAllTutorialsTest(){ From 29a33c3407035423a79ead55f14692647ccead0f Mon Sep 17 00:00:00 2001 From: Micah Silverman Date: Mon, 27 Jun 2016 02:30:09 -0400 Subject: [PATCH 022/269] Made BaseController to provide uniform exception response. Made JwtResponse for uniform responses. Added ensureType method to enforce type on registered claims. --- .../jjwtfun/JJWTFunApplication.java | 6 +- .../jjwtfun/controller/BaseController.java | 23 ++++++ .../controller/DynamicJWTController.java | 51 ++++++++++---- .../controller/StaticJWTController.java | 35 +++------- .../jjwtfun/model/JwtResponse.java | 70 +++++++++++++++++++ 5 files changed, 143 insertions(+), 42 deletions(-) create mode 100644 jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/BaseController.java create mode 100644 jjwt/src/main/java/io/jsonwebtoken/jjwtfun/model/JwtResponse.java diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/JJWTFunApplication.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/JJWTFunApplication.java index 7189617d55..5c106aac70 100644 --- a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/JJWTFunApplication.java +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/JJWTFunApplication.java @@ -6,7 +6,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class JJWTFunApplication { - public static void main(String[] args) { - SpringApplication.run(JJWTFunApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(JJWTFunApplication.class, args); + } } diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/BaseController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/BaseController.java new file mode 100644 index 0000000000..e1e195c6ab --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/BaseController.java @@ -0,0 +1,23 @@ +package io.jsonwebtoken.jjwtfun.controller; + +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.MalformedJwtException; +import io.jsonwebtoken.SignatureException; +import io.jsonwebtoken.jjwtfun.model.JwtResponse; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; + +public class BaseController { + + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler({SignatureException.class, MalformedJwtException.class, JwtException.class}) + public JwtResponse exception(Exception e) { + JwtResponse response = new JwtResponse(); + response.setStatus(JwtResponse.Status.ERROR); + response.setMessage(e.getMessage()); + response.setExceptionType(e.getClass().getName()); + + return response; + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java index fff7e1d6a2..72bc491b00 100644 --- a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java @@ -1,8 +1,10 @@ package io.jsonwebtoken.jjwtfun.controller; import io.jsonwebtoken.JwtBuilder; +import io.jsonwebtoken.JwtException; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.jjwtfun.model.JwtResponse; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -16,47 +18,55 @@ import java.util.Map; import static org.springframework.web.bind.annotation.RequestMethod.POST; @RestController -public class DynamicJWTController { +public class DynamicJWTController extends BaseController { @Value("#{ @environment['jjwtfun.secret'] ?: 'secret' }") String secret; @RequestMapping(value = "/dynamic-builder-general", method = POST) - public String dynamicBuilderGeneric(@RequestBody Map claims) throws UnsupportedEncodingException { - return Jwts.builder() + public JwtResponse dynamicBuilderGeneric(@RequestBody Map claims) throws UnsupportedEncodingException { + String jws = Jwts.builder() .setClaims(claims) .signWith( SignatureAlgorithm.HS256, secret.getBytes("UTF-8") ) .compact(); + return new JwtResponse(jws); } @RequestMapping(value = "/dynamic-builder-specific", method = POST) - public String dynamicBuilderSpecific(@RequestBody Map claims) throws UnsupportedEncodingException { + public JwtResponse dynamicBuilderSpecific(@RequestBody Map claims) throws UnsupportedEncodingException { JwtBuilder builder = Jwts.builder(); claims.forEach((key, value) -> { switch (key) { case "iss": - builder.setIssuer((String)value); + ensureType(key, value, String.class); + builder.setIssuer((String) value); break; case "sub": - builder.setSubject((String)value); + ensureType(key, value, String.class); + builder.setSubject((String) value); break; case "aud": - builder.setAudience((String)value); + ensureType(key, value, String.class); + builder.setAudience((String) value); break; case "exp": - builder.setExpiration(Date.from(Instant.ofEpochSecond(Long.parseLong((String)value)))); + value = ensureType(key, value, Long.class); + builder.setExpiration(Date.from(Instant.ofEpochSecond((Long) value))); break; case "nbf": - builder.setNotBefore(Date.from(Instant.ofEpochSecond(Long.parseLong((String)value)))); + value = ensureType(key, value, Long.class); + builder.setNotBefore(Date.from(Instant.ofEpochSecond((Long) value))); break; case "iat": - builder.setIssuedAt(Date.from(Instant.ofEpochSecond(Long.parseLong((String)value)))); + value = ensureType(key, value, Long.class); + builder.setIssuedAt(Date.from(Instant.ofEpochSecond((Long) value))); break; case "jti": - builder.setId((String)value); + ensureType(key, value, String.class); + builder.setId((String) value); break; default: builder.claim(key, value); @@ -65,6 +75,23 @@ public class DynamicJWTController { builder.signWith(SignatureAlgorithm.HS256, secret.getBytes("UTF-8")); - return builder.compact(); + return new JwtResponse(builder.compact()); + } + + private Object ensureType(String registeredClaim, Object value, Class expectedType) { + // we want to promote Integers to Longs in this case + if (expectedType == Long.class && value instanceof Integer) { + value = ((Integer) value).longValue(); + } + + boolean isCorrectType = expectedType.isInstance(value); + + if (!isCorrectType) { + String msg = "Expected type: " + expectedType.getCanonicalName() + " for registered claim: '" + + registeredClaim + "', but got value: " + value + " of type: " + value.getClass().getCanonicalName(); + throw new JwtException(msg); + } + + return value; } } diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java index 114900285f..960ac46043 100644 --- a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java @@ -3,65 +3,46 @@ package io.jsonwebtoken.jjwtfun.controller; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jws; import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.MalformedJwtException; import io.jsonwebtoken.SignatureAlgorithm; -import io.jsonwebtoken.SignatureException; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ExceptionHandler; +import io.jsonwebtoken.jjwtfun.model.JwtResponse; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import java.io.UnsupportedEncodingException; import java.time.Instant; -import java.time.temporal.ChronoUnit; import java.util.Date; -import java.util.HashMap; -import java.util.Map; import static org.springframework.web.bind.annotation.RequestMethod.GET; -import static org.springframework.web.bind.annotation.RequestMethod.POST; @RestController -public class StaticJWTController { +public class StaticJWTController extends BaseController { @RequestMapping(value = "/static-builder", method = GET) - public String fixedBuilder() throws UnsupportedEncodingException { + public JwtResponse fixedBuilder() throws UnsupportedEncodingException { String jws = Jwts.builder() .setIssuer("Stormpath") .setSubject("msilverman") .claim("name", "Micah Silverman") .claim("scope", "admins") - .setIssuedAt(Date.from(Instant.ofEpochSecond(1466796822))) // Fri Jun 24 2016 15:33:42 GMT-0400 (EDT) - .setExpiration(Date.from(Instant.ofEpochSecond(1466883222))) // Sat Jun 25 2016 15:33:42 GMT-0400 (EDT) + .setIssuedAt(Date.from(Instant.ofEpochSecond(1466796822L))) // Fri Jun 24 2016 15:33:42 GMT-0400 (EDT) + .setExpiration(Date.from(Instant.ofEpochSecond(4622470422L))) // Sat Jun 24 2116 15:33:42 GMT-0400 (EDT) .signWith( SignatureAlgorithm.HS256, "secret".getBytes("UTF-8") ) .compact(); - return jws; + return new JwtResponse(jws); } @RequestMapping(value = "/parser", method = GET) - public Jws fixedParser(@RequestParam String jws) throws UnsupportedEncodingException { + public JwtResponse fixedParser(@RequestParam String jws) throws UnsupportedEncodingException { Jws claims = Jwts.parser() .setSigningKey("secret".getBytes("UTF-8")) .parseClaimsJws(jws); - return claims; - } - - @ResponseStatus(HttpStatus.BAD_REQUEST) - @ExceptionHandler({SignatureException.class, MalformedJwtException.class}) - public Map exception(Exception e) { - Map response = new HashMap<>(); - response.put("status", "ERROR"); - response.put("message", e.getMessage()); - response.put("exception-type", e.getClass().getName()); - return response; + return new JwtResponse(claims); } } diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/model/JwtResponse.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/model/JwtResponse.java new file mode 100644 index 0000000000..4c664bc5f7 --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/model/JwtResponse.java @@ -0,0 +1,70 @@ +package io.jsonwebtoken.jjwtfun.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class JwtResponse { + private String message; + private Status status; + private String exceptionType; + private String jwt; + private Jws claims; + + public enum Status { + SUCCESS, ERROR + } + + public JwtResponse() {} + + public JwtResponse(String jwt) { + this.jwt = jwt; + this.status = Status.SUCCESS; + } + + public JwtResponse(Jws claims) { + this.claims = claims; + this.status = Status.SUCCESS; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } + + public String getExceptionType() { + return exceptionType; + } + + public void setExceptionType(String exceptionType) { + this.exceptionType = exceptionType; + } + + public String getJwt() { + return jwt; + } + + public void setJwt(String jwt) { + this.jwt = jwt; + } + + public Jws getClaims() { + return claims; + } + + public void setClaims(Jws claims) { + this.claims = claims; + } +} From 14905fae11672ad54eee5fdaf2bddee28abccc7a Mon Sep 17 00:00:00 2001 From: Micah Silverman Date: Mon, 27 Jun 2016 09:05:44 -0400 Subject: [PATCH 023/269] Simplified type checking. --- .../controller/DynamicJWTController.java | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java index 72bc491b00..184b4b1055 100644 --- a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java @@ -41,31 +41,31 @@ public class DynamicJWTController extends BaseController { claims.forEach((key, value) -> { switch (key) { case "iss": - ensureType(key, value, String.class); + ensureType(key, value, String.class); builder.setIssuer((String) value); break; case "sub": - ensureType(key, value, String.class); + ensureType(key, value, String.class); builder.setSubject((String) value); break; case "aud": - ensureType(key, value, String.class); + ensureType(key, value, String.class); builder.setAudience((String) value); break; case "exp": - value = ensureType(key, value, Long.class); - builder.setExpiration(Date.from(Instant.ofEpochSecond((Long) value))); + ensureType(key, value, Long.class); + builder.setExpiration(Date.from(Instant.ofEpochSecond(Long.parseLong(value.toString())))); break; case "nbf": - value = ensureType(key, value, Long.class); - builder.setNotBefore(Date.from(Instant.ofEpochSecond((Long) value))); + ensureType(key, value, Long.class); + builder.setNotBefore(Date.from(Instant.ofEpochSecond(Long.parseLong(value.toString())))); break; case "iat": - value = ensureType(key, value, Long.class); - builder.setIssuedAt(Date.from(Instant.ofEpochSecond((Long) value))); + ensureType(key, value, Long.class); + builder.setIssuedAt(Date.from(Instant.ofEpochSecond(Long.parseLong(value.toString())))); break; case "jti": - ensureType(key, value, String.class); + ensureType(key, value, String.class); builder.setId((String) value); break; default: @@ -78,20 +78,15 @@ public class DynamicJWTController extends BaseController { return new JwtResponse(builder.compact()); } - private Object ensureType(String registeredClaim, Object value, Class expectedType) { - // we want to promote Integers to Longs in this case - if (expectedType == Long.class && value instanceof Integer) { - value = ((Integer) value).longValue(); - } - - boolean isCorrectType = expectedType.isInstance(value); + private void ensureType(String registeredClaim, Object value, Class expectedType) { + boolean isCorrectType = + expectedType.isInstance(value) || + expectedType == Long.class && value instanceof Integer; if (!isCorrectType) { String msg = "Expected type: " + expectedType.getCanonicalName() + " for registered claim: '" + registeredClaim + "', but got value: " + value + " of type: " + value.getClass().getCanonicalName(); throw new JwtException(msg); } - - return value; } } From 6a057f33b1e8cc2d717997cf82979eeb57a6f491 Mon Sep 17 00:00:00 2001 From: Micah Silverman Date: Mon, 27 Jun 2016 09:21:42 -0400 Subject: [PATCH 024/269] Set configurable secret for parsing. --- .../jjwtfun/controller/StaticJWTController.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java index 960ac46043..9bf4ab2e45 100644 --- a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java @@ -5,6 +5,7 @@ import io.jsonwebtoken.Jws; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.jjwtfun.model.JwtResponse; +import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -18,6 +19,9 @@ import static org.springframework.web.bind.annotation.RequestMethod.GET; @RestController public class StaticJWTController extends BaseController { + @Value("#{ @environment['jjwtfun.secret'] ?: 'secret' }") + String secret; + @RequestMapping(value = "/static-builder", method = GET) public JwtResponse fixedBuilder() throws UnsupportedEncodingException { @@ -38,10 +42,10 @@ public class StaticJWTController extends BaseController { } @RequestMapping(value = "/parser", method = GET) - public JwtResponse fixedParser(@RequestParam String jws) throws UnsupportedEncodingException { + public JwtResponse parser(@RequestParam String jwt) throws UnsupportedEncodingException { Jws claims = Jwts.parser() - .setSigningKey("secret".getBytes("UTF-8")) - .parseClaimsJws(jws); + .setSigningKey(secret.getBytes("UTF-8")) + .parseClaimsJws(jwt); return new JwtResponse(claims); } From f1630a0199f96fb179c1279e9db1b32311262509 Mon Sep 17 00:00:00 2001 From: Micah Silverman Date: Mon, 27 Jun 2016 13:26:58 -0400 Subject: [PATCH 025/269] Added support for JWT CSRF in Spring Security --- jjwt/pom.xml | 6 ++ .../jjwtfun/config/CSRFConfig.java | 25 ++++++ .../config/JWTCsrfTokenRepository.java | 76 +++++++++++++++++++ .../jjwtfun/config/WebSecurityConfig.java | 23 ++++++ .../jjwtfun/controller/FormController.java | 26 +++++++ .../resources/templates/fragments/head.html | 21 +++++ .../templates/jwt-csrf-form-result.html | 18 +++++ .../resources/templates/jwt-csrf-form.html | 18 +++++ 8 files changed, 213 insertions(+) create mode 100644 jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/CSRFConfig.java create mode 100644 jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/JWTCsrfTokenRepository.java create mode 100644 jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/WebSecurityConfig.java create mode 100644 jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FormController.java create mode 100644 jjwt/src/main/resources/templates/fragments/head.html create mode 100644 jjwt/src/main/resources/templates/jwt-csrf-form-result.html create mode 100644 jjwt/src/main/resources/templates/jwt-csrf-form.html diff --git a/jjwt/pom.xml b/jjwt/pom.xml index 0764194803..24f1c5c5ab 100644 --- a/jjwt/pom.xml +++ b/jjwt/pom.xml @@ -28,11 +28,17 @@ org.springframework.boot spring-boot-devtools + org.springframework.boot spring-boot-starter-thymeleaf + + org.springframework.boot + spring-boot-starter-security + + org.springframework.boot spring-boot-starter-test diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/CSRFConfig.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/CSRFConfig.java new file mode 100644 index 0000000000..1a8f05359c --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/CSRFConfig.java @@ -0,0 +1,25 @@ +package io.jsonwebtoken.jjwtfun.config; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.web.csrf.CsrfTokenRepository; + +@Configuration +public class CSRFConfig { + + + private static final Logger log = LoggerFactory.getLogger(CSRFConfig.class); + + @Value("#{ @environment['jjwtfun.secret'] ?: 'secret' }") + String secret; + + @Bean + @ConditionalOnMissingBean + public CsrfTokenRepository jwtCsrfTokenRepository() { + return new JWTCsrfTokenRepository(secret); + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/JWTCsrfTokenRepository.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/JWTCsrfTokenRepository.java new file mode 100644 index 0000000000..2489beb76e --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/JWTCsrfTokenRepository.java @@ -0,0 +1,76 @@ +package io.jsonwebtoken.jjwtfun.config; + +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.web.csrf.CsrfToken; +import org.springframework.security.web.csrf.CsrfTokenRepository; +import org.springframework.security.web.csrf.DefaultCsrfToken; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.UnsupportedEncodingException; +import java.util.Date; +import java.util.UUID; + +public class JWTCsrfTokenRepository implements CsrfTokenRepository { + + private static final Logger log = LoggerFactory.getLogger(JWTCsrfTokenRepository.class); + private static final String DEFAULT_CSRF_TOKEN_ATTR_NAME = CSRFConfig.class.getName().concat(".CSRF_TOKEN"); + + private String secret; + + public JWTCsrfTokenRepository(String secret) { + this.secret = secret; + } + + @Override + public CsrfToken generateToken(HttpServletRequest request) { + + String id = UUID.randomUUID().toString().replace("-", ""); + + Date now = new Date(); + Date exp = new Date(System.currentTimeMillis() + (1000*60)); // 1 minute + + String token; + try { + token = Jwts.builder() + .setId(id) + .setIssuedAt(now) + .setNotBefore(now) + .setExpiration(exp) + .signWith(SignatureAlgorithm.HS256, secret.getBytes("UTF-8")) + .compact(); + } catch (UnsupportedEncodingException e) { + log.error("Unable to create CSRf JWT: {}", e.getMessage(), e); + token = id; + } + + return new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", token); + } + + @Override + public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) { + if (token == null) { + HttpSession session = request.getSession(false); + if (session != null) { + session.removeAttribute(DEFAULT_CSRF_TOKEN_ATTR_NAME); + } + } + else { + HttpSession session = request.getSession(); + session.setAttribute(DEFAULT_CSRF_TOKEN_ATTR_NAME, token); + } + } + + @Override + public CsrfToken loadToken(HttpServletRequest request) { + HttpSession session = request.getSession(false); + if (session == null) { + return null; + } + return (CsrfToken) session.getAttribute(DEFAULT_CSRF_TOKEN_ATTR_NAME); + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/WebSecurityConfig.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/WebSecurityConfig.java new file mode 100644 index 0000000000..2715990d38 --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/WebSecurityConfig.java @@ -0,0 +1,23 @@ +package io.jsonwebtoken.jjwtfun.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.csrf.CsrfTokenRepository; + +@Configuration +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Autowired + CsrfTokenRepository jwtCsrfTokenRepository; + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .csrf().csrfTokenRepository(jwtCsrfTokenRepository).and() + .authorizeRequests() + .antMatchers("/**") + .permitAll(); + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FormController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FormController.java new file mode 100644 index 0000000000..178af2f48d --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FormController.java @@ -0,0 +1,26 @@ +package io.jsonwebtoken.jjwtfun.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import static org.springframework.web.bind.annotation.RequestMethod.GET; +import static org.springframework.web.bind.annotation.RequestMethod.POST; + +@Controller +public class FormController { + + @RequestMapping(value = "/jwt-csrf-form", method = GET) + public String csrfFormGet() { + return "jwt-csrf-form"; + } + + @RequestMapping(value = "/jwt-csrf-form", method = POST) + public String csrfFormPost(@RequestParam(name = "_csrf") String csrf, Model model) { + + model.addAttribute("csrf", csrf); + + return "jwt-csrf-form-result"; + } +} diff --git a/jjwt/src/main/resources/templates/fragments/head.html b/jjwt/src/main/resources/templates/fragments/head.html new file mode 100644 index 0000000000..ce76b0e655 --- /dev/null +++ b/jjwt/src/main/resources/templates/fragments/head.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + +

Nothing to see here, move along.

+ + \ No newline at end of file diff --git a/jjwt/src/main/resources/templates/jwt-csrf-form-result.html b/jjwt/src/main/resources/templates/jwt-csrf-form-result.html new file mode 100644 index 0000000000..6547459c27 --- /dev/null +++ b/jjwt/src/main/resources/templates/jwt-csrf-form-result.html @@ -0,0 +1,18 @@ + + + + + + +
+
+
+

You made it!

+
+

BLARG

+
+
+
+
+ + \ No newline at end of file diff --git a/jjwt/src/main/resources/templates/jwt-csrf-form.html b/jjwt/src/main/resources/templates/jwt-csrf-form.html new file mode 100644 index 0000000000..dcdb664647 --- /dev/null +++ b/jjwt/src/main/resources/templates/jwt-csrf-form.html @@ -0,0 +1,18 @@ + + + + + + +
+
+
+

+

+ +
+
+
+
+ + \ No newline at end of file From 38e829ef35a09e705c95c639da6410a157b90fdc Mon Sep 17 00:00:00 2001 From: Micah Silverman Date: Mon, 27 Jun 2016 18:51:07 -0400 Subject: [PATCH 026/269] Added JWT CSRF expired handling. --- .../jjwtfun/config/CSRFConfig.java | 5 -- .../config/JWTCsrfTokenRepository.java | 6 +- .../jjwtfun/config/WebSecurityConfig.java | 57 +++++++++++++++++-- .../jjwtfun/controller/FormController.java | 7 ++- .../main/resources/templates/expired-jwt.html | 17 ++++++ .../resources/templates/fragments/head.html | 11 ++++ .../templates/jwt-csrf-form-result.html | 2 +- .../resources/templates/jwt-csrf-form.html | 2 +- 8 files changed, 91 insertions(+), 16 deletions(-) create mode 100644 jjwt/src/main/resources/templates/expired-jwt.html diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/CSRFConfig.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/CSRFConfig.java index 1a8f05359c..b3d3bdedfd 100644 --- a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/CSRFConfig.java +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/CSRFConfig.java @@ -1,7 +1,5 @@ package io.jsonwebtoken.jjwtfun.config; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; @@ -11,9 +9,6 @@ import org.springframework.security.web.csrf.CsrfTokenRepository; @Configuration public class CSRFConfig { - - private static final Logger log = LoggerFactory.getLogger(CSRFConfig.class); - @Value("#{ @environment['jjwtfun.secret'] ?: 'secret' }") String secret; diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/JWTCsrfTokenRepository.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/JWTCsrfTokenRepository.java index 2489beb76e..0a68e4624d 100644 --- a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/JWTCsrfTokenRepository.java +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/JWTCsrfTokenRepository.java @@ -17,9 +17,9 @@ import java.util.UUID; public class JWTCsrfTokenRepository implements CsrfTokenRepository { - private static final Logger log = LoggerFactory.getLogger(JWTCsrfTokenRepository.class); private static final String DEFAULT_CSRF_TOKEN_ATTR_NAME = CSRFConfig.class.getName().concat(".CSRF_TOKEN"); + private static final Logger log = LoggerFactory.getLogger(JWTCsrfTokenRepository.class); private String secret; public JWTCsrfTokenRepository(String secret) { @@ -32,7 +32,7 @@ public class JWTCsrfTokenRepository implements CsrfTokenRepository { String id = UUID.randomUUID().toString().replace("-", ""); Date now = new Date(); - Date exp = new Date(System.currentTimeMillis() + (1000*60)); // 1 minute + Date exp = new Date(System.currentTimeMillis() + (1000*30)); // 30 seconds String token; try { @@ -68,7 +68,7 @@ public class JWTCsrfTokenRepository implements CsrfTokenRepository { @Override public CsrfToken loadToken(HttpServletRequest request) { HttpSession session = request.getSession(false); - if (session == null) { + if (session == null || "GET".equals(request.getMethod())) { return null; } return (CsrfToken) session.getAttribute(DEFAULT_CSRF_TOKEN_ATTR_NAME); diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/WebSecurityConfig.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/WebSecurityConfig.java index 2715990d38..c09e8cd179 100644 --- a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/WebSecurityConfig.java +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/WebSecurityConfig.java @@ -1,23 +1,72 @@ package io.jsonwebtoken.jjwtfun.config; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.Jwts; 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.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.csrf.CsrfFilter; +import org.springframework.security.web.csrf.CsrfToken; import org.springframework.security.web.csrf.CsrfTokenRepository; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; @Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + @Value("#{ @environment['jjwtfun.secret'] ?: 'secret' }") + String secret; + @Autowired CsrfTokenRepository jwtCsrfTokenRepository; @Override protected void configure(HttpSecurity http) throws Exception { http - .csrf().csrfTokenRepository(jwtCsrfTokenRepository).and() - .authorizeRequests() - .antMatchers("/**") - .permitAll(); + .addFilterAfter(new JwtCsrfValidatorFilter(), CsrfFilter.class) + .csrf() + .csrfTokenRepository(jwtCsrfTokenRepository) + .ignoringAntMatchers("/dynamic-builder-general") + .ignoringAntMatchers("/dynamic-builder-specific") + .and().authorizeRequests() + .antMatchers("/**") + .permitAll(); + } + + private class JwtCsrfValidatorFilter extends OncePerRequestFilter { + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + // NOTE: A real implementation should have a nonce cache so the token cannot be reused + + CsrfToken token = (CsrfToken) request.getAttribute("_csrf"); + + // CsrfFilter already made sure the token matched. + // Here, we'll make sure it's not expired + if ("POST".equals(request.getMethod()) && token != null) { + try { + Jwts.parser() + .setSigningKey(secret.getBytes("UTF-8")) + .parseClaimsJws(token.getToken()); + } catch (JwtException e) { + // most likely an ExpiredJwtException, but this will handle any + request.setAttribute("exception", e); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + RequestDispatcher dispatcher = request.getRequestDispatcher("expired-jwt"); + dispatcher.forward(request, response); + } + } + + filterChain.doFilter(request, response); + } } } diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FormController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FormController.java index 178af2f48d..54123c63cb 100644 --- a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FormController.java +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FormController.java @@ -18,9 +18,12 @@ public class FormController { @RequestMapping(value = "/jwt-csrf-form", method = POST) public String csrfFormPost(@RequestParam(name = "_csrf") String csrf, Model model) { - model.addAttribute("csrf", csrf); - return "jwt-csrf-form-result"; } + + @RequestMapping("/expired-jwt") + public String expiredJwt() { + return "expired-jwt"; + } } diff --git a/jjwt/src/main/resources/templates/expired-jwt.html b/jjwt/src/main/resources/templates/expired-jwt.html new file mode 100644 index 0000000000..7bf9ff258e --- /dev/null +++ b/jjwt/src/main/resources/templates/expired-jwt.html @@ -0,0 +1,17 @@ + + + + + +
+
+
+

JWT CSRF Token expired

+

+ + Back +
+
+
+ + \ No newline at end of file diff --git a/jjwt/src/main/resources/templates/fragments/head.html b/jjwt/src/main/resources/templates/fragments/head.html index ce76b0e655..2d5f54e5a0 100644 --- a/jjwt/src/main/resources/templates/fragments/head.html +++ b/jjwt/src/main/resources/templates/fragments/head.html @@ -8,6 +8,17 @@ + + + + - log4j - log4j - 1.2.16 + org.springframework.boot + spring-boot-starter-test + test + + org.springframework.data + spring-data-neo4j + ${spring-data-neo4j.version} + test-jar + + + + org.neo4j + neo4j-kernel + ${neo4j.version} + test-jar + + + + org.neo4j.app + neo4j-server + ${neo4j.version} + test-jar + + + + org.neo4j + neo4j-ogm-test + 2.0.2 + test + + + + org.neo4j.test + neo4j-harness + ${neo4j.version} + test + + + junit + junit + 4.12 + junit junit 4.12 - org.springframework spring-test - ${spring.version} + 4.2.3.RELEASE + - + + + + + maven-compiler-plugin + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + spring-milestones + http://repo.spring.io/libs-snapshot + + true + + + + + + spring-milestones + http://repo.spring.io/libs-snapshot + + true + + + diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/LibraryNeo4jConfiguration.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/LibraryNeo4jConfiguration.java deleted file mode 100644 index c497c944d1..0000000000 --- a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/LibraryNeo4jConfiguration.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.baeldung.spring.data.neo4j.config; - - -import org.neo4j.ogm.session.SessionFactory; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.data.neo4j.config.Neo4jConfiguration; -import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; -import org.springframework.data.neo4j.server.Neo4jServer; -import org.springframework.data.neo4j.server.RemoteServer; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.transaction.annotation.EnableTransactionManagement; - - -@Configuration -@ComponentScan("com.baeldung.spring.data.neo4j") -@EnableNeo4jRepositories(basePackages = "com.baeldung.spring.data.neo4j.repostory") -public class LibraryNeo4jConfiguration extends Neo4jConfiguration { - - public static final String URL = System.getenv("NEO4J_URL") != null ? System.getenv("NEO4J_URL") : "http://localhost:7474"; - - @Override - public Neo4jServer neo4jServer() { - return new RemoteServer(URL,"neo4j","password"); - } - - @Override - public SessionFactory getSessionFactory() { - return new SessionFactory("com.baeldung.spring.data.neo4j.model"); - } -} \ No newline at end of file diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jConfiguration.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jConfiguration.java new file mode 100644 index 0000000000..6e57eb1f36 --- /dev/null +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jConfiguration.java @@ -0,0 +1,38 @@ +package com.baeldung.spring.data.neo4j.config; + +import org.neo4j.ogm.session.SessionFactory; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.config.Neo4jConfiguration; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.transaction.annotation.EnableTransactionManagement; + + +@EnableTransactionManagement +@EnableScheduling +@EnableAutoConfiguration +@ComponentScan(basePackages = {"com.baeldung.spring.data.neo4j.services"}) +@Configuration +@EnableNeo4jRepositories(basePackages = "com.baeldung.spring.data.neo4j.repostory") +public class MovieDatabaseNeo4jConfiguration extends Neo4jConfiguration { + + public static final String URL = System.getenv("NEO4J_URL") != null ? System.getenv("NEO4J_URL") : "http://neo4j:movies@localhost:7474"; + + @Bean + public org.neo4j.ogm.config.Configuration getConfiguration() { + org.neo4j.ogm.config.Configuration config = new org.neo4j.ogm.config.Configuration(); + config + .driverConfiguration() + .setDriverClassName("org.neo4j.ogm.drivers.http.driver.HttpDriver") + .setURI(URL); + return config; + } + + @Override + public SessionFactory getSessionFactory() { + return new SessionFactory(getConfiguration(), "com.baeldung.spring.data.neo4j.domain"); + } +} diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jTestConfiguration.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jTestConfiguration.java new file mode 100644 index 0000000000..2b6394184d --- /dev/null +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jTestConfiguration.java @@ -0,0 +1,34 @@ +package com.baeldung.spring.data.neo4j.config; + +import org.neo4j.ogm.session.SessionFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.data.neo4j.config.Neo4jConfiguration; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.server.Neo4jServer; +import org.springframework.transaction.annotation.EnableTransactionManagement; + + +@EnableTransactionManagement +@ComponentScan(basePackages = {"com.baeldung.spring.data.neo4j.services"}) +@Configuration +@EnableNeo4jRepositories(basePackages = "com.baeldung.spring.data.neo4j.repostory") +@Profile({"embedded", "test"}) +public class MovieDatabaseNeo4jTestConfiguration extends Neo4jConfiguration { + + @Bean + public org.neo4j.ogm.config.Configuration getConfiguration() { + org.neo4j.ogm.config.Configuration config = new org.neo4j.ogm.config.Configuration(); + config + .driverConfiguration() + .setDriverClassName("org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver"); + return config; + } + + @Override + public SessionFactory getSessionFactory() { + return new SessionFactory(getConfiguration(), "com.baeldung.spring.data.neo4j.domain"); + } +} diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Movie.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Movie.java new file mode 100644 index 0000000000..8d68b69c05 --- /dev/null +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Movie.java @@ -0,0 +1,63 @@ +package com.baeldung.spring.data.neo4j.domain; + +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.voodoodyne.jackson.jsog.JSOGGenerator; +import org.neo4j.ogm.annotation.GraphId; +import org.neo4j.ogm.annotation.NodeEntity; +import org.neo4j.ogm.annotation.Relationship; + +import java.util.Collection; +import java.util.List; + +@JsonIdentityInfo(generator=JSOGGenerator.class) + +@NodeEntity +public class Movie { + @GraphId + Long id; + + private String title; + + private int released; + private String tagline; + + @Relationship(type="ACTED_IN", direction = Relationship.INCOMING) private List roles; + +// end::movie[] + + public Movie() { } + + public String getTitle() { + return title; + } + + public int getReleased() { + return released; + } + + public String getTagline() { + return tagline; + } + + public Collection getRoles() { + return roles; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setReleased(int released) { + this.released = released; + } + + public void setTagline(String tagline) { + this.tagline = tagline; + } + + public void setRoles(List roles) { + this.roles = roles; + } + + +} diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Person.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Person.java new file mode 100644 index 0000000000..d96dc07530 --- /dev/null +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Person.java @@ -0,0 +1,50 @@ +package com.baeldung.spring.data.neo4j.domain; + + +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.voodoodyne.jackson.jsog.JSOGGenerator; +import org.neo4j.ogm.annotation.GraphId; +import org.neo4j.ogm.annotation.NodeEntity; +import org.neo4j.ogm.annotation.Relationship; + +import java.util.List; + +@JsonIdentityInfo(generator=JSOGGenerator.class) +@NodeEntity +public class Person { + @GraphId + Long id; + + private String name; + private int born; + + @Relationship(type = "ACTED_IN") + private List movies; + + public Person() { } + + public String getName() { + return name; + } + + public int getBorn() { + return born; + } + + public List getMovies() { + return movies; + } + + public void setName(String name) { + this.name = name; + } + + public void setBorn(int born) { + this.born = born; + } + + public void setMovies(List movies) { + this.movies = movies; + } + +} diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Role.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Role.java new file mode 100644 index 0000000000..20512a10ad --- /dev/null +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Role.java @@ -0,0 +1,50 @@ +package com.baeldung.spring.data.neo4j.domain; + + +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.voodoodyne.jackson.jsog.JSOGGenerator; +import org.neo4j.ogm.annotation.EndNode; +import org.neo4j.ogm.annotation.GraphId; +import org.neo4j.ogm.annotation.RelationshipEntity; +import org.neo4j.ogm.annotation.StartNode; + +import java.util.Collection; + +@JsonIdentityInfo(generator=JSOGGenerator.class) +@RelationshipEntity(type = "ACTED_IN") +public class Role { + @GraphId + Long id; + private Collection roles; + @StartNode + private Person person; + @EndNode + private Movie movie; + + public Role() { + } + + public Collection getRoles() { + return roles; + } + + public Person getPerson() { + return person; + } + + public Movie getMovie() { + return movie; + } + + public void setRoles(Collection roles) { + this.roles = roles; + } + + public void setPerson(Person person) { + this.person = person; + } + + public void setMovie(Movie movie) { + this.movie = movie; + } +} diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/model/Book.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/model/Book.java deleted file mode 100644 index 2c643a4b7c..0000000000 --- a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/model/Book.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.baeldung.spring.data.neo4j.model; - -import org.neo4j.graphdb.Direction; -import org.neo4j.ogm.annotation.*; - -import java.util.Collection; -import java.util.List; -import java.util.concurrent.atomic.AtomicLong; - -@NodeEntity -public class Book { - - private static final AtomicLong TS = new AtomicLong(); - - @GraphId - private Long id; - private String title; - private int released; - - @Relationship(type="AUTHORED_BY", direction = Relationship.INCOMING) - private Person person; - - public Book() { - this.id = TS.getAndIncrement(); - } - - public Long getId() { - return id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public int getReleased() { - return released; - } - - public void setReleased(int released) { - this.released = released; - } - - public Person getPerson() { - return person; - } - - public void setPerson(Person person) { - this.person = person; - } -} \ No newline at end of file diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/model/Person.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/model/Person.java deleted file mode 100644 index 53444c8f6c..0000000000 --- a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/model/Person.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.baeldung.spring.data.neo4j.model; - -import org.neo4j.ogm.annotation.*; - -import java.util.List; -import java.util.concurrent.atomic.AtomicLong; - -@NodeEntity -public class Person { - - private static final AtomicLong TS = new AtomicLong(); - - @GraphId - private Long id; - private String name; - private int born; - - @Relationship(type = "AUTHORED_BY") - private List books; - - public Person() { - this.id = TS.incrementAndGet(); - } - - public Long getId() { - return id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getBorn() { - return born; - } - - public void setBorn(int born) { - this.born = born; - } - - public List getBooks() { - return books; - } - - public void setBooks(List books) { - this.books = books; - } -} diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/BookRepository.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/BookRepository.java deleted file mode 100644 index c76d2862fc..0000000000 --- a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/BookRepository.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.baeldung.spring.data.neo4j.repostory; - -import com.baeldung.spring.data.neo4j.model.Book; -import org.springframework.data.neo4j.annotation.Query; -import org.springframework.data.neo4j.repository.GraphRepository; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; - -import java.util.Collection; -import java.util.List; -import java.util.Map; - -@Repository -public interface BookRepository extends GraphRepository { - -} \ No newline at end of file diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/MovieRepository.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/MovieRepository.java new file mode 100644 index 0000000000..3c5953eff3 --- /dev/null +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/MovieRepository.java @@ -0,0 +1,25 @@ +package com.baeldung.spring.data.neo4j.repostory; + +import com.baeldung.spring.data.neo4j.domain.Movie; +import org.springframework.data.neo4j.annotation.Query; +import org.springframework.data.neo4j.repository.GraphRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.data.rest.core.annotation.RepositoryRestResource; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + + +@RepositoryRestResource(collectionResourceRel = "movies", path = "movies") +public interface MovieRepository extends GraphRepository { + Movie findByTitle(@Param("title") String title); + + @Query("MATCH (m:Movie) WHERE m.title =~ ('(?i).*'+{title}+'.*') RETURN m") + Collection findByTitleContaining(@Param("title") String title); + + @Query("MATCH (m:Movie)<-[:ACTED_IN]-(a:Person) RETURN m.title as movie, collect(a.name) as cast LIMIT {limit}") + List> graph(@Param("limit") int limit); +} + + diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/PersonRepository.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/PersonRepository.java new file mode 100644 index 0000000000..4c287f99a4 --- /dev/null +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/PersonRepository.java @@ -0,0 +1,11 @@ +package com.baeldung.spring.data.neo4j.repostory; + +import com.baeldung.spring.data.neo4j.domain.Person; +import org.springframework.data.neo4j.repository.GraphRepository; +import org.springframework.stereotype.Repository; + + +@Repository +public interface PersonRepository extends GraphRepository { + +} diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookService.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookService.java deleted file mode 100644 index daa988c92d..0000000000 --- a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookService.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.baeldung.spring.data.neo4j.service; - -import com.baeldung.spring.data.neo4j.model.Book; - -import java.util.Map; - -public interface BookService { - - Book save(Book book); - - void delete(long bookId); - - long bookCount(); - - Book findBookById(Long id); - - void deleteAllInGraph(); -} diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookServiceImpl.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookServiceImpl.java deleted file mode 100644 index 0c07e4acd9..0000000000 --- a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/service/BookServiceImpl.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.baeldung.spring.data.neo4j.service; - - -import com.baeldung.spring.data.neo4j.model.Book; -import com.baeldung.spring.data.neo4j.repostory.BookRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.*; - -@Service -public class BookServiceImpl implements BookService { - - @Autowired - private BookRepository bookRepository; - - public Book save(final Book book){ - return bookRepository.save(book); - } - - public long bookCount(){ - return bookRepository.count(); - } - - public Book findBookById(final Long id){ - return bookRepository.findOne(id); - } - - public void delete(final long bookId){ - bookRepository.delete(bookId); - } - - public void deleteAllInGraph(){ - bookRepository.deleteAll(); - } - - -} \ No newline at end of file diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/services/MovieService.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/services/MovieService.java new file mode 100644 index 0000000000..532cc79091 --- /dev/null +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/services/MovieService.java @@ -0,0 +1,50 @@ +package com.baeldung.spring.data.neo4j.services; + +import com.baeldung.spring.data.neo4j.repostory.MovieRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +@Service +@Transactional +public class MovieService { + + @Autowired + MovieRepository movieRepository; + + private Map toD3Format(Iterator> result) { + List> nodes = new ArrayList>(); + List> rels= new ArrayList>(); + int i=0; + while (result.hasNext()) { + Map row = result.next(); + nodes.add(map("title",row.get("movie"),"label","movie")); + int target=i; + i++; + for (Object name : (Collection) row.get("cast")) { + Map actor = map("title", name,"label","actor"); + int source = nodes.indexOf(actor); + if (source == -1) { + nodes.add(actor); + source = i++; + } + rels.add(map("source",source,"target",target)); + } + } + return map("nodes", nodes, "links", rels); + } + + private Map map(String key1, Object value1, String key2, Object value2) { + Map result = new HashMap(2); + result.put(key1,value1); + result.put(key2,value2); + return result; + } + + public Map graph(int limit) { + Iterator> result = movieRepository.graph(limit).iterator(); + return toD3Format(result); + } +} diff --git a/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/BookServiceTest.java b/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/BookServiceTest.java deleted file mode 100644 index 17c75a1921..0000000000 --- a/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/BookServiceTest.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.baeldung.spring.data.neo4j; - -import com.baeldung.spring.data.neo4j.config.LibraryNeo4jConfiguration; -import com.baeldung.spring.data.neo4j.model.Book; -import com.baeldung.spring.data.neo4j.model.Person; -import com.baeldung.spring.data.neo4j.service.BookService; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = LibraryNeo4jConfiguration.class) -public class BookServiceTest { - - @Autowired - private BookService bookServiceImpl; - - @Test - public void testSavingBook() { - final Person author1 = new Person(); - author1.setName("Mark Twain"); - author1.setBorn(1835); - final Book book = new Book(); - book.setTitle("The Adventures of Tom Sawyer"); - book.setReleased(1876); - book.setPerson(author1); - - final Book savedBook = bookServiceImpl.save(book); - assertEquals(book.getTitle(), savedBook.getTitle()); - } - - @Test - public void testFindingTheSavedBook() { - final Person author1 = new Person(); - author1.setName("Edgar Allan Poe"); - author1.setBorn(1809); - final Book book = new Book(); - book.setTitle("The Cask of Amontillado"); - book.setReleased(1846); - book.setPerson(author1); - - bookServiceImpl.save(book); - final Book retrievedBook = bookServiceImpl.findBookById(book.getId()); - assertEquals(book.getTitle(), retrievedBook.getTitle()); - } - - @Test - public void testCountTheSavedBooks() { - long bookCount = bookServiceImpl.bookCount(); - assertEquals(bookCount, 2); - } - @Test - public void testDeletingASavedBook() { - final Person author1 = new Person(); - author1.setName("Rider Haggard"); - author1.setBorn(1856); - final Book book = new Book(); - book.setTitle("King Solomon's Mines"); - book.setReleased(1885); - book.setPerson(author1); - - final Book savedBook = bookServiceImpl.save(book); - bookServiceImpl.delete(savedBook.getId()); - final Book retrievedBook = bookServiceImpl.findBookById(book.getId()); - assertNull(retrievedBook); - } - - @Test - public void testDeleteAllSavedBook() { - bookServiceImpl.deleteAllInGraph(); - final long bookCount = bookServiceImpl.bookCount(); - assertEquals(bookCount, 0); - } -} diff --git a/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryTest.java b/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryTest.java new file mode 100644 index 0000000000..4f09284b6a --- /dev/null +++ b/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryTest.java @@ -0,0 +1,131 @@ +package com.baeldung.spring.data.neo4j; + +import com.baeldung.spring.data.neo4j.config.MovieDatabaseNeo4jTestConfiguration; +import com.baeldung.spring.data.neo4j.domain.Movie; +import com.baeldung.spring.data.neo4j.domain.Person; +import com.baeldung.spring.data.neo4j.domain.Role; +import com.baeldung.spring.data.neo4j.repostory.MovieRepository; +import com.baeldung.spring.data.neo4j.repostory.PersonRepository; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.*; + +import static junit.framework.TestCase.assertNull; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = MovieDatabaseNeo4jTestConfiguration.class) +@ActiveProfiles(profiles = "test") +public class MovieRepositoryTest { + + @Autowired + private MovieRepository instance; + + @Autowired + private PersonRepository personRepository; + + public MovieRepositoryTest() { + } + + @Before + public void initializeDatabase() { + System.out.println("seeding embedded database"); + Movie matrix = new Movie(); + matrix.setTitle("The Italian Job"); + matrix.setReleased(1999); + instance.save(matrix); + + Person mark = new Person(); + mark.setName("Mark Wahlberg"); + personRepository.save(mark); + + Role neo = new Role(); + neo.setMovie(matrix); + neo.setPerson(mark); + Collection roleNames = new HashSet(); + roleNames.add("Charlie Croker"); + neo.setRoles(roleNames); + List roles = new ArrayList(); + roles.add(neo); + matrix.setRoles(roles); + instance.save(matrix); + } + + @Test + @DirtiesContext + public void testFindByTitle() { + System.out.println("findByTitle"); + String title = "The Italian Job"; + Movie result = instance.findByTitle(title); + assertNotNull(result); + assertEquals(1999, result.getReleased()); + } + + @Test + @DirtiesContext + public void testCount() { + System.out.println("count"); + long result = instance.count(); + assertNotNull(result); + assertEquals(1, result); + } + + @Test + @DirtiesContext + public void testFindAll() { + System.out.println("findAll"); + Collection result = (Collection) instance.findAll(); + assertNotNull(result); + assertEquals(1, result.size()); + } + + @Test + @DirtiesContext + public void testFindByTitleContaining() { + System.out.println("findByTitleContaining"); + String title = "Italian"; + Collection result = instance.findByTitleContaining(title); + assertNotNull(result); + assertEquals(1,result.size()); + } + + @Test + @DirtiesContext + public void testGraph() { + System.out.println("graph"); + List> graph = instance.graph(5); + assertEquals(1,graph.size()); + Map map = graph.get(0); + assertEquals(2,map.size()); + String[] cast = (String[])map.get("cast"); + String movie = (String)map.get("movie"); + assertEquals("The Italian Job",movie); + assertEquals("Mark Wahlberg", cast[0]); + } + + @Test + @DirtiesContext + public void testDeleteMovie() { + System.out.println("deleteMovie"); + instance.delete( + instance.findByTitle("The Italian Job")); + assertNull(instance.findByTitle("The Italian Job")); + } + + @Test + @DirtiesContext + public void testDeleteAll() { + System.out.println("deleteAll"); + instance.deleteAll(); + Collection result = (Collection) instance.findAll(); + assertEquals(0,result.size()); + } +} From 6d897e664b78f0771224f78b38238eb11b3c1704 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:14:10 +0300 Subject: [PATCH 030/269] Update README.md --- httpclient/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/httpclient/README.md b/httpclient/README.md index e06c57da71..a848edfea6 100644 --- a/httpclient/README.md +++ b/httpclient/README.md @@ -1,7 +1,9 @@ ========= - ## HttpClient 4.x Cookbooks and Examples +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring + ### Relevant Articles: From d232553cbf0a34ea30277600106f3f9d91992a80 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:16:18 +0300 Subject: [PATCH 031/269] Update README.md --- jackson/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jackson/README.md b/jackson/README.md index 53b9c7c31d..68765de686 100644 --- a/jackson/README.md +++ b/jackson/README.md @@ -2,6 +2,9 @@ ## Jackson Cookbooks and Examples +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring + ### 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) From 594ab38b16d5a4bd66c2b4405c05c59af65f6e23 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:20:19 +0300 Subject: [PATCH 032/269] Update README.md --- rest-testing/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rest-testing/README.md b/rest-testing/README.md index db7f0c8a86..54a2e98dda 100644 --- a/rest-testing/README.md +++ b/rest-testing/README.md @@ -2,6 +2,8 @@ ## REST Testing and Examples +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles: - [Test a REST API with Java](http://www.baeldung.com/2011/10/13/integration-testing-a-rest-api/) From 49e996888f586ecf25d29917c93a3f32d73e70de Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:21:06 +0300 Subject: [PATCH 033/269] Update README.md --- spring-all/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spring-all/README.md b/spring-all/README.md index 977b8b7357..3188d0a42c 100644 --- a/spring-all/README.md +++ b/spring-all/README.md @@ -2,6 +2,9 @@ ## Spring General Example Project +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring + This project is used to replicate Spring Exceptions only. From 92d44e3dcdbe415532864ac12434d26f5c04a219 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:21:31 +0300 Subject: [PATCH 034/269] Update README.md --- spring-all/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spring-all/README.md b/spring-all/README.md index 3188d0a42c..47c947a414 100644 --- a/spring-all/README.md +++ b/spring-all/README.md @@ -2,11 +2,10 @@ ## Spring General Example Project -###The Course -The "REST With Spring" Classes: http://bit.ly/restwithspring - This project is used to replicate Spring Exceptions only. +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring ### 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 From 862c13eb9244f0f57bc927adceb8038fb390c9ea Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:22:26 +0300 Subject: [PATCH 035/269] Update README.md --- spring-data-rest/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spring-data-rest/README.md b/spring-data-rest/README.md index d9be83113b..7dc439206b 100644 --- a/spring-data-rest/README.md +++ b/spring-data-rest/README.md @@ -1,3 +1,6 @@ +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring + # About this project This project contains examples from the [Introduction to Spring Data REST](http://www.baeldung.com/spring-data-rest-intro) article from Baeldung. From 413ccc79c268aef96df59eba9b3024555a13f40f Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:24:40 +0300 Subject: [PATCH 036/269] Update README.md --- spring-katharsis/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spring-katharsis/README.md b/spring-katharsis/README.md index ec0141f41a..cf2a001760 100644 --- a/spring-katharsis/README.md +++ b/spring-katharsis/README.md @@ -2,5 +2,8 @@ ## Java Web Application +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring + ### Relevant Articles: - [JSON API in a Java Web Application](http://www.baeldung.com/json-api-java-spring-web-app) From 7d1d6327174b6be40435eaa2748cc0dcdc923799 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:26:30 +0300 Subject: [PATCH 037/269] Create README.MD --- raml/README.MD | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 raml/README.MD diff --git a/raml/README.MD b/raml/README.MD new file mode 100644 index 0000000000..2a87b46021 --- /dev/null +++ b/raml/README.MD @@ -0,0 +1,2 @@ +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring From 779b8ecfd64ca93367ea0fbc86c964c39e5f7a4b Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:27:04 +0300 Subject: [PATCH 038/269] Create README.MD --- spring-boot/README.MD | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 spring-boot/README.MD diff --git a/spring-boot/README.MD b/spring-boot/README.MD new file mode 100644 index 0000000000..2a87b46021 --- /dev/null +++ b/spring-boot/README.MD @@ -0,0 +1,2 @@ +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring From 46d5938ab63335c214e0903020a176b38cf2784d Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:27:43 +0300 Subject: [PATCH 039/269] Update README.md --- spring-mvc-java/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-mvc-java/README.md b/spring-mvc-java/README.md index e5264b0370..951d80033e 100644 --- a/spring-mvc-java/README.md +++ b/spring-mvc-java/README.md @@ -2,6 +2,8 @@ ## Spring MVC with Java Configuration Example Project +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles: - [Spring Bean Annotations](http://www.baeldung.com/spring-bean-annotations) From 2d65d5227434b6b8ba63dedd60edfaedd20dd72c Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:28:30 +0300 Subject: [PATCH 040/269] Update README.md --- spring-mvc-no-xml/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spring-mvc-no-xml/README.md b/spring-mvc-no-xml/README.md index 5ffe2385b5..208cb35f78 100644 --- a/spring-mvc-no-xml/README.md +++ b/spring-mvc-no-xml/README.md @@ -2,6 +2,8 @@ ## Spring MVC with NO XML Configuration Example Project +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles: -- \ No newline at end of file +- From 1f2666090c39959d0782d90c302979bcbe7d4f54 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:29:00 +0300 Subject: [PATCH 041/269] Update README.md --- spring-mvc-xml/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spring-mvc-xml/README.md b/spring-mvc-xml/README.md index 2409ec8174..ce823a9682 100644 --- a/spring-mvc-xml/README.md +++ b/spring-mvc-xml/README.md @@ -1,5 +1,8 @@ ========= +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring + ## Spring MVC with XML Configuration Example Project - access a sample jsp page at: `http://localhost:8080/spring-mvc-xml/sample.html` From 96e903feebb8e4441530558ec4775e9061bd819e Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:29:36 +0300 Subject: [PATCH 042/269] Create README.MD --- spring-rest-docs/README.MD | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 spring-rest-docs/README.MD diff --git a/spring-rest-docs/README.MD b/spring-rest-docs/README.MD new file mode 100644 index 0000000000..2a87b46021 --- /dev/null +++ b/spring-rest-docs/README.MD @@ -0,0 +1,2 @@ +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring From 7d7c5f3d8a86249177f0dce8ee0806a0d7c22cc4 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:30:06 +0300 Subject: [PATCH 043/269] Update README.md --- spring-rest/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-rest/README.md b/spring-rest/README.md index 9d373962c4..7d993b38b8 100644 --- a/spring-rest/README.md +++ b/spring-rest/README.md @@ -2,6 +2,8 @@ ## Spring REST Example Project +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles: - [Spring @RequestMapping](http://www.baeldung.com/spring-requestmapping) From 89cae684875290955a524217bedc6f224d2785e7 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:30:45 +0300 Subject: [PATCH 044/269] Update README.md --- spring-security-basic-auth/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spring-security-basic-auth/README.md b/spring-security-basic-auth/README.md index 95e45ae519..f3c29e1777 100644 --- a/spring-security-basic-auth/README.md +++ b/spring-security-basic-auth/README.md @@ -2,6 +2,8 @@ ## Spring Security with Basic Authentication Example Project +###The Course +The "Learn Spring Security" Classes: http://bit.ly/learnspringsecurity ### Relevant Article: - [Spring Security - security none, filters none, access permitAll](http://www.baeldung.com/security-none-filters-none-access-permitAll) @@ -9,4 +11,4 @@ ### Notes -- the project includes both views as well as a REST layer \ No newline at end of file +- the project includes both views as well as a REST layer From 134a4a0e1ae2415491596fbdb3172fde3b2e8c16 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:31:19 +0300 Subject: [PATCH 045/269] Create README.MD --- spring-security-client/README.MD | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 spring-security-client/README.MD diff --git a/spring-security-client/README.MD b/spring-security-client/README.MD new file mode 100644 index 0000000000..2a87b46021 --- /dev/null +++ b/spring-security-client/README.MD @@ -0,0 +1,2 @@ +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring From 4e183efda376f63d89dc25e8565e6927eee2f401 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:32:12 +0300 Subject: [PATCH 046/269] Create README.MD --- spring-scurity-custom-permission/README.MD | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 spring-scurity-custom-permission/README.MD diff --git a/spring-scurity-custom-permission/README.MD b/spring-scurity-custom-permission/README.MD new file mode 100644 index 0000000000..8fb14fa522 --- /dev/null +++ b/spring-scurity-custom-permission/README.MD @@ -0,0 +1,2 @@ +###The Course +The "Learn Spring Security" Classes: http://bit.ly/learnspringsecurity From f0e103b1911e8eb808f6d4d955a055a2cf350646 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:32:45 +0300 Subject: [PATCH 047/269] Update README.md --- spring-security-mvc-custom/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-security-mvc-custom/README.md b/spring-security-mvc-custom/README.md index 17f32e4a2f..cbf5fc6a97 100644 --- a/spring-security-mvc-custom/README.md +++ b/spring-security-mvc-custom/README.md @@ -2,6 +2,8 @@ ## Spring Security Login Example Project +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles: - [Spring Security Remember Me](http://www.baeldung.com/spring-security-remember-me) From 915fa89f8949c6ca5966ad93df3cee64d6dbaa50 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:33:11 +0300 Subject: [PATCH 048/269] Update README.md --- spring-security-rest-custom/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spring-security-rest-custom/README.md b/spring-security-rest-custom/README.md index f19af32d41..38dc638e8d 100644 --- a/spring-security-rest-custom/README.md +++ b/spring-security-rest-custom/README.md @@ -2,6 +2,9 @@ ## Spring Security for REST Example Project +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring + ### Relevant Articles: - [Spring Security Authentication Provider](http://www.baeldung.com/spring-security-authentication-provider) - [Retrieve User Information in Spring Security](http://www.baeldung.com/get-user-in-spring-security) From 5b80cbd556d8bd95afa08e09daada41310ce9559 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:33:40 +0300 Subject: [PATCH 049/269] Update README.md --- spring-security-mvc-digest-auth/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-security-mvc-digest-auth/README.md b/spring-security-mvc-digest-auth/README.md index 3b93a84505..21835266bf 100644 --- a/spring-security-mvc-digest-auth/README.md +++ b/spring-security-mvc-digest-auth/README.md @@ -2,6 +2,8 @@ ## Spring Security with Digest Authentication Example Project +###The Course +The "Learn Spring Security" Classes: http://bit.ly/learnspringsecurity ### Relevant Article: - [Spring Security Digest Authentication](http://www.baeldung.com/spring-security-digest-authentication) From 71e18a28a09e8d447ad21c0650b6398ca4535177 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:34:22 +0300 Subject: [PATCH 050/269] Update README.md --- spring-security-mvc-ldap/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-security-mvc-ldap/README.md b/spring-security-mvc-ldap/README.md index 686f611f99..1eb3b75405 100644 --- a/spring-security-mvc-ldap/README.md +++ b/spring-security-mvc-ldap/README.md @@ -1,6 +1,8 @@ ## Spring Security with LDAP Example Project +###The Course +The "Learn Spring Security" Classes: http://bit.ly/learnspringsecurity ### Relevant Article: - [Spring Security - security none, filters none, access permitAll](http://www.baeldung.com/security-none-filters-none-access-permitAll) From 2018411b14a8e10f7b64aed233403a1c74f7e378 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:35:04 +0300 Subject: [PATCH 051/269] Update README.md --- spring-security-mvc-login/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spring-security-mvc-login/README.md b/spring-security-mvc-login/README.md index 256078f4b6..448c25d27b 100644 --- a/spring-security-mvc-login/README.md +++ b/spring-security-mvc-login/README.md @@ -2,11 +2,13 @@ ## Spring Security Login Example Project +###The Course +The "Learn Spring Security" Classes: http://bit.ly/learnspringsecurity ### Relevant Articles: - [Spring Security Form Login](http://www.baeldung.com/spring-security-login) - [Spring Security Logout](http://www.baeldung.com/spring-security-logout) -- [Spring Security Expressions – hasRole Example](http://www.baeldung.com/spring-security-expressions-basic) +- [Spring Security Expressions – hasRole Example](http://www.baeldung.com/spring-security-expressions-basic) ### Build the Project From 4c912d8a5107e8c11837efa3ae5fb698547779c8 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:35:35 +0300 Subject: [PATCH 052/269] Update README.md --- spring-security-mvc-persisted-remember-me/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-security-mvc-persisted-remember-me/README.md b/spring-security-mvc-persisted-remember-me/README.md index df83fd3d77..0d5f4f5f0e 100644 --- a/spring-security-mvc-persisted-remember-me/README.md +++ b/spring-security-mvc-persisted-remember-me/README.md @@ -2,6 +2,8 @@ ## Spring Security Persisted Remember Me Example Project +###The Course +The "Learn Spring Security" Classes: http://bit.ly/learnspringsecurity ### Relevant Articles: - [Spring Security Persisted Remember Me](http://www.baeldung.com/spring-security-persistent-remember-me) From ed9a36bd31738271a47b89cfc7f575edb1280fdb Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:36:02 +0300 Subject: [PATCH 053/269] Update README.md --- spring-security-mvc-session/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spring-security-mvc-session/README.md b/spring-security-mvc-session/README.md index 0df728688a..28f216c130 100644 --- a/spring-security-mvc-session/README.md +++ b/spring-security-mvc-session/README.md @@ -2,9 +2,11 @@ ## Spring Security Login Example Project +###The Course +The "Learn Spring Security" Classes: http://bit.ly/learnspringsecurity ### Relevant Articles: -- [HttpSessionListener Example – Monitoring](http://www.baeldung.com/httpsessionlistener_with_metrics) +- [HttpSessionListener Example – Monitoring](http://www.baeldung.com/httpsessionlistener_with_metrics) - [Spring Security Session Management](http://www.baeldung.com/spring-security-session) From 4162c4671e9bff40e950cd19e3850617ab6bb234 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:36:31 +0300 Subject: [PATCH 054/269] Update README.md --- spring-security-rest-basic-auth/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-security-rest-basic-auth/README.md b/spring-security-rest-basic-auth/README.md index 723bcebbdd..9621773d91 100644 --- a/spring-security-rest-basic-auth/README.md +++ b/spring-security-rest-basic-auth/README.md @@ -2,6 +2,8 @@ ## REST API with Basic Authentication - Example Project +###The Course +The "Learn Spring Security" Classes: http://bit.ly/learnspringsecurity ### Relevant Articles: - [RestTemplate with Basic Authentication in Spring](http://www.baeldung.com/2012/04/16/how-to-use-resttemplate-with-basic-authentication-in-spring-3-1) From e3fc9bca7de968c634819edfbed483fdcf6b0d5e Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:36:58 +0300 Subject: [PATCH 055/269] Update README.md --- spring-security-rest-digest-auth/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-security-rest-digest-auth/README.md b/spring-security-rest-digest-auth/README.md index 06e847edad..4fdc934fe5 100644 --- a/spring-security-rest-digest-auth/README.md +++ b/spring-security-rest-digest-auth/README.md @@ -2,6 +2,8 @@ ## REST API with Digest Authentication - Example Project +###The Course +The "Learn Spring Security" Classes: http://bit.ly/learnspringsecurity ### Relevant Articles: - [RestTemplate with Digest Authentication](http://www.baeldung.com/resttemplate-digest-authentication) From 9b7cf1152d2709df58b0e8bab9503ded68343d55 Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:37:34 +0300 Subject: [PATCH 056/269] Update README.md --- spring-security-rest-full/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spring-security-rest-full/README.md b/spring-security-rest-full/README.md index 72e8636df1..ca18ebe79a 100644 --- a/spring-security-rest-full/README.md +++ b/spring-security-rest-full/README.md @@ -2,8 +2,9 @@ ## REST Example Project with Spring Security -### The Course - The "REST With Spring" Classes: http://bit.ly/restwithspring +### Courses +The "REST With Spring" Classes: http://bit.ly/restwithspring +The "Learn Spring Security" Classes: http://bit.ly/learnspringsecurity ### Relevant Articles: - [Spring Security Expressions - hasRole Example](http://www.baeldung.com/spring-security-expressions-basic) From ea0907bd383cd5fbcfcf111fbba084932f34852c Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:38:19 +0300 Subject: [PATCH 057/269] Update README.md --- spring-security-rest-full/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-security-rest-full/README.md b/spring-security-rest-full/README.md index ca18ebe79a..947d32e87c 100644 --- a/spring-security-rest-full/README.md +++ b/spring-security-rest-full/README.md @@ -4,6 +4,7 @@ ### Courses The "REST With Spring" Classes: http://bit.ly/restwithspring + The "Learn Spring Security" Classes: http://bit.ly/learnspringsecurity ### Relevant Articles: From a79e7b7ea24ba8285a858d1ef06d52165b86969b Mon Sep 17 00:00:00 2001 From: m0cacin0 Date: Tue, 28 Jun 2016 12:38:51 +0300 Subject: [PATCH 058/269] Update README.md --- spring-security-rest/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spring-security-rest/README.md b/spring-security-rest/README.md index 290cd491e0..87f14a9047 100644 --- a/spring-security-rest/README.md +++ b/spring-security-rest/README.md @@ -2,6 +2,10 @@ ## Spring Security for REST Example Project +### Courses +The "REST With Spring" Classes: http://bit.ly/restwithspring + +The "Learn Spring Security" Classes: http://bit.ly/learnspringsecurity ### 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/) From 1a3e005442fc76b9b1428eb21fd94a8bc4af81fe Mon Sep 17 00:00:00 2001 From: Sameera Date: Tue, 28 Jun 2016 23:17:24 +0530 Subject: [PATCH 059/269] updating test cases --- spring-data-neo4j/pom.xml | 42 ------------------- .../MovieDatabaseNeo4jConfiguration.java | 2 - .../data/neo4j/repostory/MovieRepository.java | 2 - .../data/neo4j/MovieRepositoryTest.java | 12 +++--- 4 files changed, 7 insertions(+), 51 deletions(-) diff --git a/spring-data-neo4j/pom.xml b/spring-data-neo4j/pom.xml index 320b6ce019..a5a2e9220a 100644 --- a/spring-data-neo4j/pom.xml +++ b/spring-data-neo4j/pom.xml @@ -13,15 +13,8 @@ UTF-8 3.0.1 4.1.1.RELEASE - Hopper-SR1 - - org.springframework.boot - spring-boot-starter-parent - 1.3.0.RELEASE - - org.springframework.data @@ -29,11 +22,6 @@ ${spring-data-neo4j.version} - - org.springframework.boot - spring-boot-starter-data-rest - - com.voodoodyne.jackson.jsog jackson-jsog @@ -41,9 +29,6 @@ compile - - - org.springframework.boot spring-boot-starter-test @@ -89,11 +74,6 @@ junit 4.12 - - junit - junit - 4.12 - org.springframework spring-test @@ -107,29 +87,7 @@ maven-compiler-plugin - - org.springframework.boot - spring-boot-maven-plugin - - - - spring-milestones - http://repo.spring.io/libs-snapshot - - true - - - - - - spring-milestones - http://repo.spring.io/libs-snapshot - - true - - - diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jConfiguration.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jConfiguration.java index 6e57eb1f36..003e72971a 100644 --- a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jConfiguration.java +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jConfiguration.java @@ -1,7 +1,6 @@ package com.baeldung.spring.data.neo4j.config; import org.neo4j.ogm.session.SessionFactory; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -13,7 +12,6 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; @EnableTransactionManagement @EnableScheduling -@EnableAutoConfiguration @ComponentScan(basePackages = {"com.baeldung.spring.data.neo4j.services"}) @Configuration @EnableNeo4jRepositories(basePackages = "com.baeldung.spring.data.neo4j.repostory") diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/MovieRepository.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/MovieRepository.java index 3c5953eff3..90833d7c70 100644 --- a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/MovieRepository.java +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/MovieRepository.java @@ -4,14 +4,12 @@ import com.baeldung.spring.data.neo4j.domain.Movie; import org.springframework.data.neo4j.annotation.Query; import org.springframework.data.neo4j.repository.GraphRepository; import org.springframework.data.repository.query.Param; -import org.springframework.data.rest.core.annotation.RepositoryRestResource; import java.util.Collection; import java.util.List; import java.util.Map; -@RepositoryRestResource(collectionResourceRel = "movies", path = "movies") public interface MovieRepository extends GraphRepository { Movie findByTitle(@Param("title") String title); diff --git a/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryTest.java b/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryTest.java index 4f09284b6a..53ef380dbd 100644 --- a/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryTest.java +++ b/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryTest.java @@ -82,7 +82,8 @@ public class MovieRepositoryTest { @DirtiesContext public void testFindAll() { System.out.println("findAll"); - Collection result = (Collection) instance.findAll(); + Collection result = + (Collection) instance.findAll(); assertNotNull(result); assertEquals(1, result.size()); } @@ -92,7 +93,8 @@ public class MovieRepositoryTest { public void testFindByTitleContaining() { System.out.println("findByTitleContaining"); String title = "Italian"; - Collection result = instance.findByTitleContaining(title); + Collection result = + instance.findByTitleContaining(title); assertNotNull(result); assertEquals(1,result.size()); } @@ -115,8 +117,7 @@ public class MovieRepositoryTest { @DirtiesContext public void testDeleteMovie() { System.out.println("deleteMovie"); - instance.delete( - instance.findByTitle("The Italian Job")); + instance.delete(instance.findByTitle("The Italian Job")); assertNull(instance.findByTitle("The Italian Job")); } @@ -125,7 +126,8 @@ public class MovieRepositoryTest { public void testDeleteAll() { System.out.println("deleteAll"); instance.deleteAll(); - Collection result = (Collection) instance.findAll(); + Collection result = + (Collection) instance.findAll(); assertEquals(0,result.size()); } } From 548365130aa9d1230eb2c21e2915857c40a2cd9f Mon Sep 17 00:00:00 2001 From: Sameera Date: Tue, 28 Jun 2016 23:38:40 +0530 Subject: [PATCH 060/269] updating test cases --- .../data/neo4j/config/MovieDatabaseNeo4jConfiguration.java | 2 -- .../baeldung/spring/data/neo4j/repostory/MovieRepository.java | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jConfiguration.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jConfiguration.java index 003e72971a..ac9a7260be 100644 --- a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jConfiguration.java +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jConfiguration.java @@ -10,8 +10,6 @@ import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.transaction.annotation.EnableTransactionManagement; -@EnableTransactionManagement -@EnableScheduling @ComponentScan(basePackages = {"com.baeldung.spring.data.neo4j.services"}) @Configuration @EnableNeo4jRepositories(basePackages = "com.baeldung.spring.data.neo4j.repostory") diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/MovieRepository.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/MovieRepository.java index 90833d7c70..850d2336ba 100644 --- a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/MovieRepository.java +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repostory/MovieRepository.java @@ -4,12 +4,13 @@ import com.baeldung.spring.data.neo4j.domain.Movie; import org.springframework.data.neo4j.annotation.Query; import org.springframework.data.neo4j.repository.GraphRepository; import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; import java.util.Collection; import java.util.List; import java.util.Map; - +@Repository public interface MovieRepository extends GraphRepository { Movie findByTitle(@Param("title") String title); From 31b3e0fa167dc56af6b6144361db3d03382ee5d5 Mon Sep 17 00:00:00 2001 From: Sameera Date: Tue, 28 Jun 2016 23:48:45 +0530 Subject: [PATCH 061/269] updating test cases --- .../spring/data/neo4j/domain/Movie.java | 2 - .../data/neo4j/MovieRepositoryTest.java | 66 +++++++++---------- 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Movie.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Movie.java index 8d68b69c05..e48dfaf276 100644 --- a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Movie.java +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Movie.java @@ -23,8 +23,6 @@ public class Movie { @Relationship(type="ACTED_IN", direction = Relationship.INCOMING) private List roles; -// end::movie[] - public Movie() { } public String getTitle() { diff --git a/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryTest.java b/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryTest.java index 53ef380dbd..92d27d2a1e 100644 --- a/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryTest.java +++ b/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryTest.java @@ -25,38 +25,38 @@ import static org.junit.Assert.assertNotNull; @ContextConfiguration(classes = MovieDatabaseNeo4jTestConfiguration.class) @ActiveProfiles(profiles = "test") public class MovieRepositoryTest { - + @Autowired private MovieRepository instance; @Autowired private PersonRepository personRepository; - + public MovieRepositoryTest() { } - - @Before + + @Before public void initializeDatabase() { - System.out.println("seeding embedded database"); - Movie matrix = new Movie(); - matrix.setTitle("The Italian Job"); - matrix.setReleased(1999); - instance.save(matrix); - - Person mark = new Person(); - mark.setName("Mark Wahlberg"); - personRepository.save(mark); - - Role neo = new Role(); - neo.setMovie(matrix); - neo.setPerson(mark); - Collection roleNames = new HashSet(); - roleNames.add("Charlie Croker"); - neo.setRoles(roleNames); - List roles = new ArrayList(); - roles.add(neo); - matrix.setRoles(roles); - instance.save(matrix); + System.out.println("seeding embedded database"); + Movie italianJob = new Movie(); + italianJob.setTitle("The Italian Job"); + italianJob.setReleased(1999); + instance.save(italianJob); + + Person mark = new Person(); + mark.setName("Mark Wahlberg"); + personRepository.save(mark); + + Role charlie = new Role(); + charlie.setMovie(italianJob); + charlie.setPerson(mark); + Collection roleNames = new HashSet(); + roleNames.add("Charlie Croker"); + charlie.setRoles(roleNames); + List roles = new ArrayList(); + roles.add(charlie); + italianJob.setRoles(roles); + instance.save(italianJob); } @Test @@ -96,20 +96,20 @@ public class MovieRepositoryTest { Collection result = instance.findByTitleContaining(title); assertNotNull(result); - assertEquals(1,result.size()); + assertEquals(1, result.size()); } @Test @DirtiesContext public void testGraph() { System.out.println("graph"); - List> graph = instance.graph(5); - assertEquals(1,graph.size()); - Map map = graph.get(0); - assertEquals(2,map.size()); - String[] cast = (String[])map.get("cast"); - String movie = (String)map.get("movie"); - assertEquals("The Italian Job",movie); + List> graph = instance.graph(5); + assertEquals(1, graph.size()); + Map map = graph.get(0); + assertEquals(2, map.size()); + String[] cast = (String[]) map.get("cast"); + String movie = (String) map.get("movie"); + assertEquals("The Italian Job", movie); assertEquals("Mark Wahlberg", cast[0]); } @@ -128,6 +128,6 @@ public class MovieRepositoryTest { instance.deleteAll(); Collection result = (Collection) instance.findAll(); - assertEquals(0,result.size()); + assertEquals(0, result.size()); } } From d4c2d508a407e4011e1fa87937fa71287c2acff9 Mon Sep 17 00:00:00 2001 From: Sameera Date: Wed, 29 Jun 2016 00:31:38 +0530 Subject: [PATCH 062/269] updating test cases --- .../data/neo4j/MovieRepositoryTest.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryTest.java b/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryTest.java index 92d27d2a1e..8061b3c2a7 100644 --- a/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryTest.java +++ b/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryTest.java @@ -27,7 +27,7 @@ import static org.junit.Assert.assertNotNull; public class MovieRepositoryTest { @Autowired - private MovieRepository instance; + private MovieRepository movieRepository; @Autowired private PersonRepository personRepository; @@ -41,7 +41,7 @@ public class MovieRepositoryTest { Movie italianJob = new Movie(); italianJob.setTitle("The Italian Job"); italianJob.setReleased(1999); - instance.save(italianJob); + movieRepository.save(italianJob); Person mark = new Person(); mark.setName("Mark Wahlberg"); @@ -56,7 +56,7 @@ public class MovieRepositoryTest { List roles = new ArrayList(); roles.add(charlie); italianJob.setRoles(roles); - instance.save(italianJob); + movieRepository.save(italianJob); } @Test @@ -64,7 +64,7 @@ public class MovieRepositoryTest { public void testFindByTitle() { System.out.println("findByTitle"); String title = "The Italian Job"; - Movie result = instance.findByTitle(title); + Movie result = movieRepository.findByTitle(title); assertNotNull(result); assertEquals(1999, result.getReleased()); } @@ -73,9 +73,9 @@ public class MovieRepositoryTest { @DirtiesContext public void testCount() { System.out.println("count"); - long result = instance.count(); - assertNotNull(result); - assertEquals(1, result); + long movieCount = movieRepository.count(); + assertNotNull(movieCount); + assertEquals(1, movieCount); } @Test @@ -83,7 +83,7 @@ public class MovieRepositoryTest { public void testFindAll() { System.out.println("findAll"); Collection result = - (Collection) instance.findAll(); + (Collection) movieRepository.findAll(); assertNotNull(result); assertEquals(1, result.size()); } @@ -94,7 +94,7 @@ public class MovieRepositoryTest { System.out.println("findByTitleContaining"); String title = "Italian"; Collection result = - instance.findByTitleContaining(title); + movieRepository.findByTitleContaining(title); assertNotNull(result); assertEquals(1, result.size()); } @@ -103,7 +103,7 @@ public class MovieRepositoryTest { @DirtiesContext public void testGraph() { System.out.println("graph"); - List> graph = instance.graph(5); + List> graph = movieRepository.graph(5); assertEquals(1, graph.size()); Map map = graph.get(0); assertEquals(2, map.size()); @@ -117,17 +117,17 @@ public class MovieRepositoryTest { @DirtiesContext public void testDeleteMovie() { System.out.println("deleteMovie"); - instance.delete(instance.findByTitle("The Italian Job")); - assertNull(instance.findByTitle("The Italian Job")); + movieRepository.delete(movieRepository.findByTitle("The Italian Job")); + assertNull(movieRepository.findByTitle("The Italian Job")); } @Test @DirtiesContext public void testDeleteAll() { System.out.println("deleteAll"); - instance.deleteAll(); + movieRepository.deleteAll(); Collection result = - (Collection) instance.findAll(); + (Collection) movieRepository.findAll(); assertEquals(0, result.size()); } } From 0ab62700ca6edb512da1db470589cad995afa7c6 Mon Sep 17 00:00:00 2001 From: Raquel Garrido Date: Tue, 28 Jun 2016 21:11:04 +0200 Subject: [PATCH 063/269] Last changes (#468) * dom4j * added more parsers * StaxParser * Jaxb binding * Jaxb binding * Finish article * apply some changes * Organize imports --- .../java/com/baeldung/xml/JaxbParser.java | 3 +- .../java/com/baeldung/xml/StaxParser.java | 2 +- .../com/baeldung/xml/binding/Tutorial.java | 8 ++- .../java/com/baeldung/xml/model/Tutorial.java | 49 ------------------- .../com/baeldung/xml/DefaultParserTest.java | 20 ++++---- .../com/baeldung/xml/Dom4JParserTest.java | 30 ++++++------ .../java/com/baeldung/xml/JDomParserTest.java | 16 +++--- .../java/com/baeldung/xml/JaxbParserTest.java | 15 +++--- .../java/com/baeldung/xml/JaxenDemoTest.java | 14 +++--- .../java/com/baeldung/xml/StaxParserTest.java | 17 ++++--- 10 files changed, 61 insertions(+), 113 deletions(-) delete mode 100644 xml/src/main/java/com/baeldung/xml/model/Tutorial.java diff --git a/xml/src/main/java/com/baeldung/xml/JaxbParser.java b/xml/src/main/java/com/baeldung/xml/JaxbParser.java index 9c06ec5fba..758ebb969c 100644 --- a/xml/src/main/java/com/baeldung/xml/JaxbParser.java +++ b/xml/src/main/java/com/baeldung/xml/JaxbParser.java @@ -2,7 +2,6 @@ package com.baeldung.xml; import java.io.File; import java.util.ArrayList; -import java.util.Date; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; @@ -40,7 +39,7 @@ public class JaxbParser { tut.setType("XML"); tut.setTitle("XML with Jaxb"); tut.setDescription("XML Binding with Jaxb"); - tut.setDate(new Date()); + tut.setDate("04/02/2015"); tut.setAuthor("Jaxb author"); tutorials.getTutorial().add(tut); diff --git a/xml/src/main/java/com/baeldung/xml/StaxParser.java b/xml/src/main/java/com/baeldung/xml/StaxParser.java index 6f83e022f8..e14d872831 100644 --- a/xml/src/main/java/com/baeldung/xml/StaxParser.java +++ b/xml/src/main/java/com/baeldung/xml/StaxParser.java @@ -17,7 +17,7 @@ import javax.xml.stream.events.EndElement; import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; -import com.baeldung.xml.model.Tutorial; +import com.baeldung.xml.binding.Tutorial; public class StaxParser { diff --git a/xml/src/main/java/com/baeldung/xml/binding/Tutorial.java b/xml/src/main/java/com/baeldung/xml/binding/Tutorial.java index c4668a9f77..7201d499d0 100644 --- a/xml/src/main/java/com/baeldung/xml/binding/Tutorial.java +++ b/xml/src/main/java/com/baeldung/xml/binding/Tutorial.java @@ -1,7 +1,5 @@ package com.baeldung.xml.binding; -import java.util.Date; - import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; @@ -11,7 +9,7 @@ public class Tutorial { private String type; private String title; private String description; - private Date date; + private String date; private String author; @@ -44,11 +42,11 @@ public class Tutorial { public void setDescription(String description) { this.description = description; } - public Date getDate() { + public String getDate() { return date; } @XmlElement - public void setDate(Date date) { + public void setDate(String date) { this.date = date; } public String getAuthor() { diff --git a/xml/src/main/java/com/baeldung/xml/model/Tutorial.java b/xml/src/main/java/com/baeldung/xml/model/Tutorial.java deleted file mode 100644 index 40a3f858cf..0000000000 --- a/xml/src/main/java/com/baeldung/xml/model/Tutorial.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.baeldung.xml.model; - -public class Tutorial { - - private String tutId; - private String type; - private String title; - private String description; - private String date; - private String author; - - - public String getTutId() { - return tutId; - } - public void setTutId(String tutId) { - this.tutId = tutId; - } - public String getType() { - return type; - } - public void setType(String type) { - this.type = type; - } - public String getTitle() { - return title; - } - public void setTitle(String title) { - this.title = title; - } - public String getDescription() { - return description; - } - public void setDescription(String description) { - this.description = description; - } - public String getDate() { - return date; - } - public void setDate(String date) { - this.date = date; - } - public String getAuthor() { - return author; - } - public void setAuthor(String author) { - this.author = author; - } -} diff --git a/xml/src/test/java/com/baeldung/xml/DefaultParserTest.java b/xml/src/test/java/com/baeldung/xml/DefaultParserTest.java index 7408e41b92..734e7a93cb 100644 --- a/xml/src/test/java/com/baeldung/xml/DefaultParserTest.java +++ b/xml/src/test/java/com/baeldung/xml/DefaultParserTest.java @@ -1,22 +1,20 @@ package com.baeldung.xml; +import static org.junit.Assert.*; + +import java.io.File; + import org.junit.Test; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import java.io.File; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - public class DefaultParserTest { - private final String fileName = "src/test/resources/example.xml"; + final String fileName = "src/test/resources/example.xml"; - private final String fileNameSpace = "src/test/resources/example_namespace.xml"; + final String fileNameSpace = "src/test/resources/example_namespace.xml"; - private DefaultParser parser; + DefaultParser parser; @Test public void getFirstLevelNodeListTest() { @@ -32,7 +30,7 @@ public class DefaultParserTest { parser = new DefaultParser(new File(fileName)); NodeList list = parser.getNodeListByTitle("XML"); - for (int i = 0; i < list.getLength(); i++) { + for (int i = 0; null != list && i < list.getLength(); i++) { Node nod = list.item(i); assertEquals("java", nod.getAttributes().getNamedItem("type").getTextContent()); assertEquals("02", nod.getAttributes().getNamedItem("tutId").getTextContent()); @@ -58,7 +56,7 @@ public class DefaultParserTest { public void getNodeListByDateTest(){ parser = new DefaultParser(new File(fileName)); NodeList list = parser.getNodeListByTitle("04022016"); - for (int i = 0; i < list.getLength(); i++) { + for (int i = 0; null != list && i < list.getLength(); i++) { Node nod = list.item(i); assertEquals("java", nod.getAttributes().getNamedItem("type").getTextContent()); assertEquals("04", nod.getAttributes().getNamedItem("tutId").getTextContent()); diff --git a/xml/src/test/java/com/baeldung/xml/Dom4JParserTest.java b/xml/src/test/java/com/baeldung/xml/Dom4JParserTest.java index 77e5fcdcda..277eca8355 100644 --- a/xml/src/test/java/com/baeldung/xml/Dom4JParserTest.java +++ b/xml/src/test/java/com/baeldung/xml/Dom4JParserTest.java @@ -1,25 +1,25 @@ package com.baeldung.xml; -import org.dom4j.Element; -import org.dom4j.Node; -import org.junit.Test; - -import java.io.File; -import java.util.List; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.io.File; +import java.util.List; + +import org.dom4j.Element; +import org.dom4j.Node; +import org.junit.Test; + public class Dom4JParserTest { - private static final String FILE_NAME = "src/test/resources/example.xml"; + final String fileName = "src/test/resources/example.xml"; - private Dom4JParser parser; + Dom4JParser parser; @Test public void getRootElementTest() { - parser = new Dom4JParser(new File(FILE_NAME)); + parser = new Dom4JParser(new File(fileName)); Element root = parser.getRootElement(); assertNotNull(root); @@ -28,7 +28,7 @@ public class Dom4JParserTest { @Test public void getFirstElementListTest() { - parser = new Dom4JParser(new File(FILE_NAME)); + parser = new Dom4JParser(new File(fileName)); List firstList = parser.getFirstElementList(); assertNotNull(firstList); @@ -38,7 +38,7 @@ public class Dom4JParserTest { @Test public void getElementByIdTest() { - parser = new Dom4JParser(new File(FILE_NAME)); + parser = new Dom4JParser(new File(fileName)); Node element = parser.getNodeById("03"); String type = element.valueOf("@type"); @@ -47,7 +47,7 @@ public class Dom4JParserTest { @Test public void getElementsListByTitleTest() { - parser = new Dom4JParser(new File(FILE_NAME)); + parser = new Dom4JParser(new File(fileName)); Node element = parser.getElementsListByTitle("XML"); assertEquals("java", element.valueOf("@type")); @@ -58,7 +58,7 @@ public class Dom4JParserTest { @Test public void generateModifiedDocumentTest() { - parser = new Dom4JParser(new File(FILE_NAME)); + parser = new Dom4JParser(new File(fileName)); parser.generateModifiedDocument(); File generatedFile = new File("src/test/resources/example_updated.xml"); @@ -73,7 +73,7 @@ public class Dom4JParserTest { @Test public void generateNewDocumentTest() { - parser = new Dom4JParser(new File(FILE_NAME)); + parser = new Dom4JParser(new File(fileName)); parser.generateNewDocument(); File newFile = new File("src/test/resources/example_new.xml"); diff --git a/xml/src/test/java/com/baeldung/xml/JDomParserTest.java b/xml/src/test/java/com/baeldung/xml/JDomParserTest.java index e4034c48f0..981458469f 100644 --- a/xml/src/test/java/com/baeldung/xml/JDomParserTest.java +++ b/xml/src/test/java/com/baeldung/xml/JDomParserTest.java @@ -1,20 +1,20 @@ package com.baeldung.xml; -import org.jdom2.Element; -import org.junit.Test; - -import java.io.File; -import java.util.List; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.io.File; +import java.util.List; + +import org.jdom2.Element; +import org.junit.Test; + public class JDomParserTest { - private final String fileName = "src/test/resources/example.xml"; + final String fileName = "src/test/resources/example.xml"; - private JDomParser parser; + JDomParser parser; @Test public void getFirstElementListTest() { diff --git a/xml/src/test/java/com/baeldung/xml/JaxbParserTest.java b/xml/src/test/java/com/baeldung/xml/JaxbParserTest.java index 6e1a201b59..6c31a7bfdd 100644 --- a/xml/src/test/java/com/baeldung/xml/JaxbParserTest.java +++ b/xml/src/test/java/com/baeldung/xml/JaxbParserTest.java @@ -1,19 +1,20 @@ package com.baeldung.xml; -import com.baeldung.xml.binding.Tutorials; -import org.junit.Test; - -import java.io.File; - import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.io.File; + +import org.junit.Test; + +import com.baeldung.xml.binding.Tutorials; + public class JaxbParserTest { - private final String fileName = "src/test/resources/example.xml"; + final String fileName = "src/test/resources/example.xml"; - private JaxbParser parser; + JaxbParser parser; @Test public void getFullDocumentTest(){ diff --git a/xml/src/test/java/com/baeldung/xml/JaxenDemoTest.java b/xml/src/test/java/com/baeldung/xml/JaxenDemoTest.java index 8a88484f11..2521fcaf8a 100644 --- a/xml/src/test/java/com/baeldung/xml/JaxenDemoTest.java +++ b/xml/src/test/java/com/baeldung/xml/JaxenDemoTest.java @@ -1,18 +1,18 @@ package com.baeldung.xml; -import org.junit.Test; - -import java.io.File; -import java.util.List; - import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.io.File; +import java.util.List; + +import org.junit.Test; + public class JaxenDemoTest { - private final String fileName = "src/test/resources/example.xml"; + final String fileName = "src/test/resources/example.xml"; - private JaxenDemo jaxenDemo; + JaxenDemo jaxenDemo; @Test public void getFirstLevelNodeListTest() { diff --git a/xml/src/test/java/com/baeldung/xml/StaxParserTest.java b/xml/src/test/java/com/baeldung/xml/StaxParserTest.java index d1080c88ac..cf7ee1ee75 100644 --- a/xml/src/test/java/com/baeldung/xml/StaxParserTest.java +++ b/xml/src/test/java/com/baeldung/xml/StaxParserTest.java @@ -1,19 +1,20 @@ package com.baeldung.xml; -import com.baeldung.xml.model.Tutorial; -import org.junit.Test; - -import java.io.File; -import java.util.List; - import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.io.File; +import java.util.List; + +import org.junit.Test; + +import com.baeldung.xml.binding.Tutorial; + public class StaxParserTest { - private final String fileName = "src/test/resources/example.xml"; + final String fileName = "src/test/resources/example.xml"; - private StaxParser parser; + StaxParser parser; @Test public void getAllTutorialsTest(){ From 51372775ca7e5aef953f8ca667da6b06c0c9e667 Mon Sep 17 00:00:00 2001 From: reymalahay Date: Wed, 1 Jun 2016 06:47:26 -0600 Subject: [PATCH 064/269] Code and related files for the dependency injection demos. --- .gitignore | 1 - .../docs/autowired-name-demo-classdiagram.png | Bin 48700 -> 0 bytes .../docs/autowired-type-demo-classdiagram.png | Bin 23197 -> 0 bytes .../docs/autowired-type-demo-classdiagram.xml | 1 - .../docs/inject-demo-classdiagram.png | Bin 38729 -> 0 bytes .../docs/inject-field-demo-classdiagram.png | Bin 19402 -> 0 bytes .../docs/inject-field-demo-classdiagram.xml | 1 - .../docs/inject-name-demo-classdiagram.png | Bin 23358 -> 0 bytes .../docs/inject-name-demo-classdiagram.xml | 1 - .../inject-qualifier-demo-classdiagram.png | Bin 37170 -> 43724 bytes .../inject-qualifier-demo-classdiagram.xml | 2 +- .../docs/resource-demo-classdiagram.png | Bin 46095 -> 0 bytes .../docs/resource-field-demo-classdiagram.png | Bin 17692 -> 0 bytes .../docs/resource-field-demo-classdiagram.xml | 1 - ...source-method-byname-demo-classdiagram.png | Bin 29579 -> 0 bytes .../resource-method-demo-classdiagram.png | Bin 19905 -> 0 bytes .../resource-method-demo-classdiagram.xml | 1 - dependency-injection/pom.xml | 2 +- ...eDemo.java => FieldAutowiredNameTest.java} | 14 ++++-- ...wiredDemo.java => FieldAutowiredTest.java} | 11 +++-- ....java => FieldQualifierAutowiredTest.java} | 16 ++++--- .../ApplicationContextTestAutowiredName.java | 9 ++++ ...licationContextTestAutowiredQualifier.java | 25 ++++++++++ .../ApplicationContextTestAutowiredType.java | 16 +++++++ .../ApplicationContextTestInjectName.java | 17 +++++++ ...ApplicationContextTestInjectQualifier.java | 23 ++++++++++ .../ApplicationContextTestInjectType.java | 16 +++++++ ...pplicationContextTestResourceNameType.java | 16 +++++++ ...plicationContextTestResourceQualifier.java | 22 +++++++++ .../AnotherArbitraryDependency.java | 3 ++ .../dependency/ArbitraryDependency.java | 3 ++ .../YetAnotherArbitraryDependency.java | 3 ++ ...ctDemo.java => FieldByNameInjectTest.java} | 14 ++++-- .../com/baeldung/inject/FieldInjectDemo.java | 27 ----------- .../com/baeldung/inject/FieldInjectTest.java | 31 +++++++++++++ ...emo.java => FieldQualifierInjectTest.java} | 18 +++++--- .../resource/FieldResourceInjectionDemo.java | 25 ---------- .../resource/FieldResourceInjectionTest.java | 31 +++++++++++++ ...ava => MethodByQualifierResourceTest.java} | 12 +++-- ...emo.java => MethodByTypeResourceTest.java} | 14 ++++-- ....java => MethodResourceInjectionTest.java} | 15 ++++-- .../baeldung/resource/NamedResourceTest.java | 13 ++++-- .../QualifierResourceInjectionDemo.java | 35 -------------- .../QualifierResourceInjectionTest.java | 43 ++++++++++++++++++ ....java => SetterResourceInjectionTest.java} | 14 ++++-- 45 files changed, 353 insertions(+), 143 deletions(-) delete mode 100644 dependency-injection/docs/autowired-name-demo-classdiagram.png delete mode 100644 dependency-injection/docs/autowired-type-demo-classdiagram.png delete mode 100644 dependency-injection/docs/autowired-type-demo-classdiagram.xml delete mode 100644 dependency-injection/docs/inject-demo-classdiagram.png delete mode 100644 dependency-injection/docs/inject-field-demo-classdiagram.png delete mode 100644 dependency-injection/docs/inject-field-demo-classdiagram.xml delete mode 100644 dependency-injection/docs/inject-name-demo-classdiagram.png delete mode 100644 dependency-injection/docs/inject-name-demo-classdiagram.xml delete mode 100644 dependency-injection/docs/resource-demo-classdiagram.png delete mode 100644 dependency-injection/docs/resource-field-demo-classdiagram.png delete mode 100644 dependency-injection/docs/resource-field-demo-classdiagram.xml delete mode 100644 dependency-injection/docs/resource-method-byname-demo-classdiagram.png delete mode 100644 dependency-injection/docs/resource-method-demo-classdiagram.png delete mode 100644 dependency-injection/docs/resource-method-demo-classdiagram.xml rename dependency-injection/src/test/java/com/baeldung/autowired/{FieldAutowiredNameDemo.java => FieldAutowiredNameTest.java} (55%) rename dependency-injection/src/test/java/com/baeldung/autowired/{FieldAutowiredDemo.java => FieldAutowiredTest.java} (63%) rename dependency-injection/src/test/java/com/baeldung/autowired/{FieldQualifierAutowiredDemo.java => FieldQualifierAutowiredTest.java} (62%) create mode 100644 dependency-injection/src/test/java/com/baeldung/configuration/ApplicationContextTestAutowiredName.java create mode 100644 dependency-injection/src/test/java/com/baeldung/configuration/ApplicationContextTestAutowiredQualifier.java create mode 100644 dependency-injection/src/test/java/com/baeldung/configuration/ApplicationContextTestAutowiredType.java create mode 100644 dependency-injection/src/test/java/com/baeldung/configuration/ApplicationContextTestInjectName.java create mode 100644 dependency-injection/src/test/java/com/baeldung/configuration/ApplicationContextTestInjectQualifier.java create mode 100644 dependency-injection/src/test/java/com/baeldung/configuration/ApplicationContextTestInjectType.java create mode 100644 dependency-injection/src/test/java/com/baeldung/configuration/ApplicationContextTestResourceNameType.java create mode 100644 dependency-injection/src/test/java/com/baeldung/configuration/ApplicationContextTestResourceQualifier.java rename dependency-injection/src/test/java/com/baeldung/inject/{FieldByNameInjectDemo.java => FieldByNameInjectTest.java} (56%) delete mode 100644 dependency-injection/src/test/java/com/baeldung/inject/FieldInjectDemo.java create mode 100644 dependency-injection/src/test/java/com/baeldung/inject/FieldInjectTest.java rename dependency-injection/src/test/java/com/baeldung/inject/{FieldQualifierInjectDemo.java => FieldQualifierInjectTest.java} (54%) delete mode 100644 dependency-injection/src/test/java/com/baeldung/resource/FieldResourceInjectionDemo.java create mode 100644 dependency-injection/src/test/java/com/baeldung/resource/FieldResourceInjectionTest.java rename dependency-injection/src/test/java/com/baeldung/resource/{MethodByQualifierResourceDemo.java => MethodByQualifierResourceTest.java} (72%) rename dependency-injection/src/test/java/com/baeldung/resource/{MethodByTypeResourceDemo.java => MethodByTypeResourceTest.java} (52%) rename dependency-injection/src/test/java/com/baeldung/resource/{MethodResourceInjectionDemo.java => MethodResourceInjectionTest.java} (53%) delete mode 100644 dependency-injection/src/test/java/com/baeldung/resource/QualifierResourceInjectionDemo.java create mode 100644 dependency-injection/src/test/java/com/baeldung/resource/QualifierResourceInjectionTest.java rename dependency-injection/src/test/java/com/baeldung/resource/{SetterResourceInjectionDemo.java => SetterResourceInjectionTest.java} (51%) diff --git a/.gitignore b/.gitignore index 319eb5ca2d..e841cc4bf5 100644 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,3 @@ target/ spring-openid/src/main/resources/application.properties .recommenders/ - diff --git a/dependency-injection/docs/autowired-name-demo-classdiagram.png b/dependency-injection/docs/autowired-name-demo-classdiagram.png deleted file mode 100644 index f367fdbf415f93423568c1df91bc5e1e693b0f8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48700 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 Y=MFcICm*DEk>$xlrR+D#GC1P*e`SQA6#xJL diff --git a/dependency-injection/docs/autowired-type-demo-classdiagram.png b/dependency-injection/docs/autowired-type-demo-classdiagram.png deleted file mode 100644 index 5f3f3415566893568d451f5ba4f7028e9b256a14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23197 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 \ No newline at end of file diff --git a/dependency-injection/docs/inject-demo-classdiagram.png b/dependency-injection/docs/inject-demo-classdiagram.png deleted file mode 100644 index 9996fdc733f23d2ced4d5587a2d0cbe4b7d552bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38729 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 \ No newline at end of file diff --git a/dependency-injection/docs/inject-name-demo-classdiagram.png b/dependency-injection/docs/inject-name-demo-classdiagram.png deleted file mode 100644 index 96a6a3425e0e6fe8ec6982cbf0470a692163abfa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23358 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