Merge branch 'master' into BAEL-2427-getCauseException

This commit is contained in:
Marcos Lopez Gonzalez 2019-05-09 16:23:47 +02:00
commit 677d696182
81 changed files with 3659 additions and 231 deletions

21
apache-olingo/Samples.md Normal file
View File

@ -0,0 +1,21 @@
## OData test URLs
This following table contains test URLs that can be used with the Olingo V2 demo project.
| URL | Description |
|------------------------------------------|-------------------------------------------------|
| `http://localhost:8180/odata/$metadata` | fetch OData metadata document |
| `http://localhost:8180/odata/CarMakers?$top=10&$skip=10` | Get 10 entities starting at offset 10 |
| `http://localhost:8180/odata/CarMakers?$count` | Return total count of entities in this set |
| `http://localhost:8180/odata/CarMakers?$filter=startswith(Name,'B')` | Return entities where the *Name* property starts with 'B' |
| `http://localhost:8180/odata/CarModels?$filter=Year eq 2008 and CarMakerDetails/Name eq 'BWM'` | Return *CarModel* entities where the *Name* property of its maker starts with 'B' |
| `http://localhost:8180/odata/CarModels(1L)?$expand=CarMakerDetails` | Return the *CarModel* with primary key '1', along with its maker|
| `http://localhost:8180/odata/CarModels(1L)?$select=Name,Sku` | Return the *CarModel* with primary key '1', returing only its *Name* and *Sku* properties |
| `http://localhost:8180/odata/CarModels?$orderBy=Name asc,Sku desc` | Return *CarModel* entities, ordered by the their *Name* and *Sku* properties |
| `http://localhost:8180/odata/CarModels?$format=json` | Return *CarModel* entities, using a JSON representation|

29
apache-olingo/olingo2/.gitignore vendored Normal file
View File

@ -0,0 +1,29 @@
HELP.md
/target/
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
/build/
### VS Code ###
.vscode/

View File

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>org.baeldung.examples.olingo2</groupId>
<artifactId>olingo2-sample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>olingo2-sample</name>
<description>Sample Olingo 2 Project</description>
<properties>
<java.version>1.8</java.version>
<olingo2.version>2.0.11</olingo2.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Olingo 2 Dependencies -->
<dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>olingo-odata2-core</artifactId>
<version>${olingo2.version}</version>
<!-- Avoid jax-rs version conflict by excluding Olingo's version -->
<exclusions>
<exclusion>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>olingo-odata2-api</artifactId>
<version>${olingo2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>olingo-odata2-jpa-processor-api</artifactId>
<version>${olingo2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>olingo-odata2-jpa-processor-core</artifactId>
<version>${olingo2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>olingo-odata2-jpa-processor-ref</artifactId>
<version>${olingo2.version}</version>
<exclusions>
<exclusion>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,298 @@
package org.baeldung.examples.olingo2;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityGraph;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.StoredProcedureQuery;
import javax.persistence.SynchronizationType;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaDelete;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.metamodel.Metamodel;
import javax.servlet.http.HttpServletRequest;
import org.apache.olingo.odata2.api.processor.ODataContext;
import org.apache.olingo.odata2.jpa.processor.api.ODataJPAContext;
import org.apache.olingo.odata2.jpa.processor.api.ODataJPAServiceFactory;
import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException;
import org.baeldung.examples.olingo2.JerseyConfig.EntityManagerFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.stereotype.Component;
/**
* ODataJPAServiceFactory implementation for our sample domain
* @author Philippe
*
*/
@Component
public class CarsODataJPAServiceFactory extends ODataJPAServiceFactory {
private static final Logger log = LoggerFactory.getLogger(CarsODataJPAServiceFactory.class);
public CarsODataJPAServiceFactory() {
// Enable detailed error messages (useful for debugging)
setDetailErrors(true);
}
/**
* This method will be called by Olingo on every request to
* initialize the ODataJPAContext that will be used.
*/
@Override
public ODataJPAContext initializeODataJPAContext() throws ODataJPARuntimeException {
log.info("[I32] >>> initializeODataJPAContext()");
ODataJPAContext ctx = getODataJPAContext();
ODataContext octx = ctx.getODataContext();
HttpServletRequest request = (HttpServletRequest)octx.getParameter(ODataContext.HTTP_SERVLET_REQUEST_OBJECT);
EntityManager em = (EntityManager)request.getAttribute(EntityManagerFilter.EM_REQUEST_ATTRIBUTE);
// Here we're passing the EM that was created by the EntityManagerFilter (see JerseyConfig)
ctx.setEntityManager(new EntityManagerWrapper(em));
ctx.setPersistenceUnitName("default");
// We're managing the EM's lifecycle, so we must inform Olingo that it should not
// try to manage transactions and/or persistence sessions
ctx.setContainerManaged(true);
return ctx;
}
static class EntityManagerWrapper implements EntityManager {
private EntityManager delegate;
public void persist(Object entity) {
log.info("[I68] persist: entity.class=" + entity.getClass()
.getSimpleName());
delegate.persist(entity);
// delegate.flush();
}
public <T> T merge(T entity) {
log.info("[I74] merge: entity.class=" + entity.getClass()
.getSimpleName());
return delegate.merge(entity);
}
public void remove(Object entity) {
log.info("[I78] remove: entity.class=" + entity.getClass()
.getSimpleName());
delegate.remove(entity);
}
public <T> T find(Class<T> entityClass, Object primaryKey) {
return delegate.find(entityClass, primaryKey);
}
public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) {
return delegate.find(entityClass, primaryKey, properties);
}
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode) {
return delegate.find(entityClass, primaryKey, lockMode);
}
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties) {
return delegate.find(entityClass, primaryKey, lockMode, properties);
}
public <T> T getReference(Class<T> entityClass, Object primaryKey) {
return delegate.getReference(entityClass, primaryKey);
}
public void flush() {
delegate.flush();
}
public void setFlushMode(FlushModeType flushMode) {
delegate.setFlushMode(flushMode);
}
public FlushModeType getFlushMode() {
return delegate.getFlushMode();
}
public void lock(Object entity, LockModeType lockMode) {
delegate.lock(entity, lockMode);
}
public void lock(Object entity, LockModeType lockMode, Map<String, Object> properties) {
delegate.lock(entity, lockMode, properties);
}
public void refresh(Object entity) {
delegate.refresh(entity);
}
public void refresh(Object entity, Map<String, Object> properties) {
delegate.refresh(entity, properties);
}
public void refresh(Object entity, LockModeType lockMode) {
delegate.refresh(entity, lockMode);
}
public void refresh(Object entity, LockModeType lockMode, Map<String, Object> properties) {
delegate.refresh(entity, lockMode, properties);
}
public void clear() {
delegate.clear();
}
public void detach(Object entity) {
delegate.detach(entity);
}
public boolean contains(Object entity) {
return delegate.contains(entity);
}
public LockModeType getLockMode(Object entity) {
return delegate.getLockMode(entity);
}
public void setProperty(String propertyName, Object value) {
delegate.setProperty(propertyName, value);
}
public Map<String, Object> getProperties() {
return delegate.getProperties();
}
public Query createQuery(String qlString) {
return delegate.createQuery(qlString);
}
public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) {
return delegate.createQuery(criteriaQuery);
}
public Query createQuery(CriteriaUpdate updateQuery) {
return delegate.createQuery(updateQuery);
}
public Query createQuery(CriteriaDelete deleteQuery) {
return delegate.createQuery(deleteQuery);
}
public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) {
return delegate.createQuery(qlString, resultClass);
}
public Query createNamedQuery(String name) {
return delegate.createNamedQuery(name);
}
public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass) {
return delegate.createNamedQuery(name, resultClass);
}
public Query createNativeQuery(String sqlString) {
return delegate.createNativeQuery(sqlString);
}
public Query createNativeQuery(String sqlString, Class resultClass) {
return delegate.createNativeQuery(sqlString, resultClass);
}
public Query createNativeQuery(String sqlString, String resultSetMapping) {
return delegate.createNativeQuery(sqlString, resultSetMapping);
}
public StoredProcedureQuery createNamedStoredProcedureQuery(String name) {
return delegate.createNamedStoredProcedureQuery(name);
}
public StoredProcedureQuery createStoredProcedureQuery(String procedureName) {
return delegate.createStoredProcedureQuery(procedureName);
}
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) {
return delegate.createStoredProcedureQuery(procedureName, resultClasses);
}
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings) {
return delegate.createStoredProcedureQuery(procedureName, resultSetMappings);
}
public void joinTransaction() {
delegate.joinTransaction();
}
public boolean isJoinedToTransaction() {
return delegate.isJoinedToTransaction();
}
public <T> T unwrap(Class<T> cls) {
return delegate.unwrap(cls);
}
public Object getDelegate() {
return delegate.getDelegate();
}
public void close() {
log.info("[I229] close");
delegate.close();
}
public boolean isOpen() {
boolean isOpen = delegate.isOpen();
log.info("[I236] isOpen: " + isOpen);
return isOpen;
}
public EntityTransaction getTransaction() {
log.info("[I240] getTransaction()");
return delegate.getTransaction();
}
public EntityManagerFactory getEntityManagerFactory() {
return delegate.getEntityManagerFactory();
}
public CriteriaBuilder getCriteriaBuilder() {
return delegate.getCriteriaBuilder();
}
public Metamodel getMetamodel() {
return delegate.getMetamodel();
}
public <T> EntityGraph<T> createEntityGraph(Class<T> rootType) {
return delegate.createEntityGraph(rootType);
}
public EntityGraph<?> createEntityGraph(String graphName) {
return delegate.createEntityGraph(graphName);
}
public EntityGraph<?> getEntityGraph(String graphName) {
return delegate.getEntityGraph(graphName);
}
public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass) {
return delegate.getEntityGraphs(entityClass);
}
public EntityManagerWrapper(EntityManager delegate) {
this.delegate = delegate;
}
}
}

View File

@ -0,0 +1,125 @@
package org.baeldung.examples.olingo2;
import java.io.IOException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.Path;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.Context;
import javax.ws.rs.ext.Provider;
import org.apache.olingo.odata2.api.ODataServiceFactory;
import org.apache.olingo.odata2.core.rest.ODataRootLocator;
import org.apache.olingo.odata2.core.rest.app.ODataApplication;
import org.glassfish.jersey.server.ResourceConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* Jersey JAX-RS configuration
* @author Philippe
*
*/
@Component
@ApplicationPath("/odata")
public class JerseyConfig extends ResourceConfig {
public JerseyConfig(CarsODataJPAServiceFactory serviceFactory, EntityManagerFactory emf) {
ODataApplication app = new ODataApplication();
app
.getClasses()
.forEach( c -> {
// Avoid using the default RootLocator, as we want
// a Spring Managed one
if ( !ODataRootLocator.class.isAssignableFrom(c)) {
register(c);
}
});
register(new CarsRootLocator(serviceFactory));
register( new EntityManagerFilter(emf));
}
/**
* This filter handles the EntityManager transaction lifecycle.
* @author Philippe
*
*/
@Provider
public static class EntityManagerFilter implements ContainerRequestFilter, ContainerResponseFilter {
private static final Logger log = LoggerFactory.getLogger(EntityManagerFilter.class);
public static final String EM_REQUEST_ATTRIBUTE = EntityManagerFilter.class.getName() + "_ENTITY_MANAGER";
private final EntityManagerFactory emf;
@Context
private HttpServletRequest httpRequest;
public EntityManagerFilter(EntityManagerFactory emf) {
this.emf = emf;
}
@Override
public void filter(ContainerRequestContext ctx) throws IOException {
log.info("[I60] >>> filter");
EntityManager em = this.emf.createEntityManager();
httpRequest.setAttribute(EM_REQUEST_ATTRIBUTE, em);
// Start a new transaction unless we have a simple GET
if (!"GET".equalsIgnoreCase(ctx.getMethod())) {
em.getTransaction()
.begin();
}
}
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
log.info("[I68] <<< filter");
EntityManager em = (EntityManager) httpRequest.getAttribute(EM_REQUEST_ATTRIBUTE);
if (!"GET".equalsIgnoreCase(requestContext.getMethod())) {
EntityTransaction t = em.getTransaction();
if (t.isActive()) {
if (!t.getRollbackOnly()) {
t.commit();
}
}
}
em.close();
}
}
@Path("/")
public static class CarsRootLocator extends ODataRootLocator {
private CarsODataJPAServiceFactory serviceFactory;
public CarsRootLocator(CarsODataJPAServiceFactory serviceFactory) {
this.serviceFactory = serviceFactory;
}
@Override
public ODataServiceFactory getServiceFactory() {
return this.serviceFactory;
}
}
}

View File

@ -0,0 +1,14 @@
package org.baeldung.examples.olingo2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class Olingo2SampleApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Olingo2SampleApplication.class);
}
}

View File

@ -0,0 +1,36 @@
package org.baeldung.examples.olingo2.domain;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import lombok.Data;
@Entity
@Data
@Table(name="car_maker")
public class CarMaker {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@NotNull
@Column(name="name")
private String name;
@OneToMany(mappedBy="maker",
orphanRemoval = true,
cascade=CascadeType.ALL)
private List<CarModel> models;
}

View File

@ -0,0 +1,38 @@
package org.baeldung.examples.olingo2.domain;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import lombok.Data;
@Entity
@Data
@Table(name="car_model")
public class CarModel {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@NotNull
private String name;
@NotNull
private Integer year;
@NotNull
private String sku;
@ManyToOne(optional=false, fetch= FetchType.LAZY)
@JoinColumn(name="maker_fk")
private CarMaker maker;
}

View File

@ -0,0 +1,12 @@
server:
port: 8180
spring:
jersey:
application-path: /odata
jpa:
show-sql: true
open-in-view: false
hibernate:
ddl-auto: update

View File

@ -0,0 +1,12 @@
insert into car_maker(id,name) values (1,'Special Motors');
insert into car_maker(id,name) values (2,'BWM');
insert into car_maker(id,name) values (3,'Dolores');
insert into car_model(id,maker_fk,name,sku,year) values(1,1,'Muze','SM001',2018);
insert into car_model(id,maker_fk,name,sku,year) values(2,1,'Empada','SM002',2008);
insert into car_model(id,maker_fk,name,sku,year) values(4,2,'BWM-100','BWM100',2008);
insert into car_model(id,maker_fk,name,sku,year) values(5,2,'BWM-200','BWM200',2009);
insert into car_model(id,maker_fk,name,sku,year) values(6,2,'BWM-300','BWM300',2008);
alter sequence hibernate_sequence restart with 100;

View File

@ -0,0 +1,16 @@
package org.baeldung.examples.olingo2;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class Olingo2SampleApplicationTests {
@Test
public void contextLoads() {
}
}

View File

@ -0,0 +1,256 @@
{
"info": {
"_postman_id": "afa8e1e5-ab0e-4f1d-8b99-b7d1f091f975",
"name": "OLingo2 - Cars",
"schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json"
},
"item": [
{
"name": "GET Metadata",
"request": {
"method": "GET",
"header": [],
"body": {
"mode": "raw",
"raw": ""
},
"url": "http://localhost:8080/odata/$metadata"
},
"response": []
},
{
"name": "GET All CarMakers",
"request": {
"method": "GET",
"header": [],
"body": {
"mode": "raw",
"raw": ""
},
"url": "http://localhost:8080/odata/CarMakers"
},
"response": []
},
{
"name": "GET Makers with Pagination",
"request": {
"method": "GET",
"header": [],
"body": {
"mode": "raw",
"raw": ""
},
"url": {
"raw": "http://localhost:8080/odata/CarMakers?$top=1&$orderby=Name&$skip=3",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"odata",
"CarMakers"
],
"query": [
{
"key": "$top",
"value": "1"
},
{
"key": "$orderby",
"value": "Name"
},
{
"key": "$skip",
"value": "3"
}
]
}
},
"response": []
},
{
"name": "GET Makers and Models",
"request": {
"method": "GET",
"header": [],
"body": {
"mode": "raw",
"raw": ""
},
"url": {
"raw": "http://localhost:8080/odata/CarMakers?$expand=CarModelDetails",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"odata",
"CarMakers"
],
"query": [
{
"key": "$expand",
"value": "CarModelDetails"
}
]
}
},
"response": []
},
{
"name": "GET Makers with filter",
"request": {
"method": "GET",
"header": [
{
"key": "Accept",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": ""
},
"url": {
"raw": "http://localhost:8080/odata/CarMakers?$filter=Name eq 'BWM'&$expand=CarModelDetails",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"odata",
"CarMakers"
],
"query": [
{
"key": "$filter",
"value": "Name eq 'BWM'"
},
{
"key": "$expand",
"value": "CarModelDetails"
}
]
}
},
"response": []
},
{
"name": "Create CarMaker",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"name": "Content-Type",
"value": "application/atom+xml",
"type": "text"
},
{
"key": "Accept",
"value": "application/atom+xml",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "<?xml version=\"1.0\" encoding=\"utf-8\" ?> \r\n<entry xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\"\r\n xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" \r\n xmlns=\"http://www.w3.org/2005/Atom\">\r\n <title type=\"text\"></title> \r\n <updated>2019-04-02T21:36:47Z</updated>\r\n <author> \r\n <name /> \r\n </author> \r\n <category term=\"default.CarMaker\"\r\n scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\" /> \r\n <content type=\"application/xml\"> \r\n <m:properties>\r\n <d:Name>Lucien</d:Name>\r\n </m:properties> \r\n </content> \r\n</entry>"
},
"url": "http://localhost:8080/odata/CarMakers"
},
"response": []
},
{
"name": "Create CarModel",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"name": "Content-Type",
"type": "text",
"value": "application/atom+xml"
},
{
"key": "Accept",
"type": "text",
"value": "application/atom+xml"
}
],
"body": {
"mode": "raw",
"raw": "<?xml version=\"1.0\" encoding=\"utf-8\" ?> \r\n<entry xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\"\r\n xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" \r\n xmlns=\"http://www.w3.org/2005/Atom\">\r\n <title type=\"text\"></title> \r\n <updated>2019-04-02T21:36:47Z</updated>\r\n <author> \r\n <name /> \r\n </author> \r\n <link href=\"CarModels(1L)/CarMakerDetails\" \r\n rel=\"http://schemas.microsoft.com/ado/2007/08/dataservices/related/CarMakerDetails\" \r\n title=\"CarMakerDetails\" \r\n type=\"application/atom+xml;type=entry\"></link> \r\n <category term=\"default.CarModel\"\r\n scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\" /> \r\n <content type=\"application/xml\"> \r\n <m:properties>\r\n\t <d:Name>Tata</d:Name>\r\n\t <d:Sku>TT101</d:Sku>\r\n\t <d:Year>2018</d:Year>\r\n </m:properties> \r\n </content> \r\n</entry>"
},
"url": "http://localhost:8080/odata/CarModels"
},
"response": []
},
{
"name": "Update CarMaker",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"name": "Content-Type",
"type": "text",
"value": "application/atom+xml"
},
{
"key": "Accept",
"type": "text",
"value": "application/atom+xml"
}
],
"body": {
"mode": "raw",
"raw": "<?xml version=\"1.0\" encoding=\"utf-8\" ?> \r\n<entry xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\"\r\n xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" \r\n xmlns=\"http://www.w3.org/2005/Atom\">\r\n <title type=\"text\"></title> \r\n <updated>2019-04-02T21:36:47Z</updated>\r\n <author> \r\n <name /> \r\n </author> \r\n <category term=\"default.CarMaker\"\r\n scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\" /> \r\n <content type=\"application/xml\"> \r\n <m:properties>\r\n <d:Id>5</d:Id>\r\n <d:Name>KaiserWagen</d:Name>\r\n </m:properties> \r\n </content> \r\n</entry>"
},
"url": "http://localhost:8080/odata/CarMakers(5L)"
},
"response": []
},
{
"name": "All CarModels",
"request": {
"method": "GET",
"header": [],
"body": {
"mode": "raw",
"raw": ""
},
"url": "http://localhost:8080/odata/CarModels"
},
"response": []
},
{
"name": "Delete CarModel",
"request": {
"method": "DELETE",
"header": [
{
"key": "Content-Type",
"name": "Content-Type",
"type": "text",
"value": "application/atom+xml"
},
{
"key": "Accept",
"type": "text",
"value": "application/atom+xml"
}
],
"body": {
"mode": "raw",
"raw": ""
},
"url": "http://localhost:8080/odata/CarModels(100L)"
},
"response": []
}
]
}

29
apache-olingo/olingo4/.gitignore vendored Normal file
View File

@ -0,0 +1,29 @@
HELP.md
/target/
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
/build/
### VS Code ###
.vscode/

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>org.baeldung.examples.olingo4</groupId>
<artifactId>olingo4-sample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>olingo4-sample</name>
<description>Sample Olingo 4 Project</description>
<properties>
<java.version>1.8</java.version>
<odata.version>4.5.0</odata.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>odata-server-api</artifactId>
<version>${odata.version}</version>
</dependency>
<dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>odata-server-core</artifactId>
<version>${odata.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>odata-commons-api</artifactId>
<version>${odata.version}</version>
</dependency>
<dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>odata-commons-core</artifactId>
<version>${odata.version}</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,20 @@
package org.baeldung.examples.olingo4;
import org.apache.olingo.server.api.OData;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.stereotype.Component;
/**
* Default implementation for ODataFactory
* @author Philippe
*
*/
@Component
public class DefaultODataFactory implements ODataFactory {
@Override
public OData newInstance() {
return OData.newInstance();
}
}

View File

@ -0,0 +1,8 @@
package org.baeldung.examples.olingo4;
import org.apache.olingo.server.api.OData;
public interface ODataFactory {
public OData newInstance();
}

View File

@ -0,0 +1,8 @@
package org.baeldung.examples.olingo4;
import org.apache.olingo.server.api.ODataHttpHandler;
public interface ODataHttpHandlerFactory {
ODataHttpHandler newInstance();
}

View File

@ -0,0 +1,42 @@
package org.baeldung.examples.olingo4;
import java.util.Collections;
import java.util.List;
import org.apache.olingo.commons.api.edm.provider.CsdlEdmProvider;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataHttpHandler;
import org.apache.olingo.server.api.ServiceMetadata;
import org.apache.olingo.server.api.processor.Processor;
import lombok.Builder;
@Builder
public class ODataHttpHandlerFactoryImpl implements ODataHttpHandlerFactory {
private final ODataFactory odataFactory;
private final CsdlEdmProvider edmProvider;
private final List<Processor> processors;
public ODataHttpHandlerFactoryImpl(ODataFactory odataFactory,CsdlEdmProvider edmProvider, List<Processor> processors) {
this.odataFactory = odataFactory;
this.edmProvider = edmProvider;
this.processors = processors;
}
@Override
public ODataHttpHandler newInstance() {
OData odata = odataFactory.newInstance();
ServiceMetadata metadata = odata.createServiceMetadata(edmProvider, Collections.emptyList());
ODataHttpHandler handler = odata.createHandler(metadata);
// Register all available processors
processors.forEach(p -> handler.register(p));
return handler;
}
}

View File

@ -0,0 +1,35 @@
package org.baeldung.examples.olingo4;
import java.util.List;
import javax.persistence.EntityManagerFactory;
import javax.servlet.http.HttpServlet;
import org.apache.olingo.commons.api.edm.provider.CsdlEdmProvider;
import org.apache.olingo.server.api.processor.Processor;
import org.baeldung.examples.olingo4.ODataHttpHandlerFactoryImpl.ODataHttpHandlerFactoryImplBuilder;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ODataServiceConfiguration {
@Bean
public ServletRegistrationBean<HttpServlet> odataServletRegistration(ODataHttpHandlerFactory factory) {
ServletRegistrationBean<HttpServlet> srb =
new ServletRegistrationBean<>(new ODataServlet(factory), "/odata/*");
srb.setLoadOnStartup(1);
return srb;
}
@Bean
public ODataHttpHandlerFactory httpHandlerFactory(CsdlEdmProvider edmProvider, ODataFactory odataFactory, List<Processor> processors) {
return new ODataHttpHandlerFactoryImplBuilder()
.edmProvider(edmProvider)
.odataFactory(odataFactory)
.processors(processors)
.build();
}
}

View File

@ -0,0 +1,38 @@
/**
*
*/
package org.baeldung.examples.olingo4;
import java.io.IOException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.olingo.server.api.ODataHttpHandler;
/**
* @author Philippe
*
*/
public class ODataServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private final ODataHttpHandlerFactory odataHttpHandlerFactory;
public ODataServlet(ODataHttpHandlerFactory factory) {
this.odataHttpHandlerFactory = factory;
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ODataHttpHandler handler = odataHttpHandlerFactory.newInstance();
handler.process(req, resp);
}
}

View File

@ -0,0 +1,13 @@
package org.baeldung.examples.olingo4;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Olingo4SampleApplication {
public static void main(String[] args) {
SpringApplication.run(Olingo4SampleApplication.class, args);
}
}

View File

@ -0,0 +1,36 @@
package org.baeldung.examples.olingo4.domain;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import lombok.Data;
@Entity
@Data
@Table(name="car_maker")
public class CarMaker {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@NotNull
@Column(name="name")
private String name;
@OneToMany(mappedBy="maker",
orphanRemoval = true,
cascade=CascadeType.ALL)
private List<CarModel> models;
}

View File

@ -0,0 +1,38 @@
package org.baeldung.examples.olingo4.domain;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import lombok.Data;
@Entity
@Data
@Table(name="car_model")
public class CarModel {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@NotNull
private String name;
@NotNull
private Integer year;
@NotNull
private String sku;
@ManyToOne(optional=false, fetch= FetchType.EAGER )
@JoinColumn(name="maker_fk")
private CarMaker maker;
}

View File

@ -0,0 +1,46 @@
package org.baeldung.examples.olingo4.edm;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.sql.Time;
import java.util.AbstractMap.SimpleEntry;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.springframework.stereotype.Component;
@Component
public class EdmTypeMapper {
public EdmPrimitiveTypeKind java2edm(Class<?> clazz) {
EdmPrimitiveTypeKind result = java2edm.get(clazz);
if ( result == null ) {
throw new IllegalArgumentException("[E19] Unsupported class mapping: class=" + clazz);
}
else {
return result;
}
}
// Static map used generate attribute metadada based on Java types
static Map<Class<?>,EdmPrimitiveTypeKind> java2edm = Collections
.unmodifiableMap(Stream.of(
new SimpleEntry<>(Boolean.class,EdmPrimitiveTypeKind.Boolean),
new SimpleEntry<>(Byte.class,EdmPrimitiveTypeKind.SByte),
new SimpleEntry<>(Date.class,EdmPrimitiveTypeKind.Date),
new SimpleEntry<>(Time.class,EdmPrimitiveTypeKind.TimeOfDay),
new SimpleEntry<>(Number.class,EdmPrimitiveTypeKind.Decimal),
new SimpleEntry<>(Float.class,EdmPrimitiveTypeKind.Single),
new SimpleEntry<>(Double.class,EdmPrimitiveTypeKind.Double),
new SimpleEntry<>(UUID.class,EdmPrimitiveTypeKind.Guid),
new SimpleEntry<>(Short.class,EdmPrimitiveTypeKind.Int16),
new SimpleEntry<>(Integer.class,EdmPrimitiveTypeKind.Int32),
new SimpleEntry<>(Long.class,EdmPrimitiveTypeKind.Int64),
new SimpleEntry<>(String.class,EdmPrimitiveTypeKind.String)
).collect(Collectors.toMap((e)-> e.getKey(),(e)-> e.getValue())));
}

View File

@ -0,0 +1,269 @@
package org.baeldung.examples.olingo4.edm;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.persistence.EntityManagerFactory;
import javax.persistence.metamodel.Attribute.PersistentAttributeType;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.Metamodel;
import javax.persistence.metamodel.PluralAttribute;
import javax.persistence.metamodel.SingularAttribute;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmProvider;
import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer;
import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainerInfo;
import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet;
import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
import org.apache.olingo.commons.api.edm.provider.CsdlNavigationProperty;
import org.apache.olingo.commons.api.edm.provider.CsdlProperty;
import org.apache.olingo.commons.api.edm.provider.CsdlPropertyRef;
import org.apache.olingo.commons.api.edm.provider.CsdlSchema;
import org.apache.olingo.commons.api.ex.ODataException;
import org.springframework.stereotype.Component;
@Component
public class JpaEdmProvider extends CsdlAbstractEdmProvider {
EntityManagerFactory emf;
//
private EdmTypeMapper typeMapper;
// Service Namespace
public static final String NAMESPACE = "Baeldung.OData";
// EDM Container
public static final String CONTAINER_NAME = "Cars";
public static final FullQualifiedName CONTAINER = new FullQualifiedName(NAMESPACE, CONTAINER_NAME);
// Caches of OData types by it fully qualified name
private Map<FullQualifiedName, CsdlEntityType> cdslName2Type = new HashMap<>();
public JpaEdmProvider(EntityManagerFactory emf, EdmTypeMapper mapper) {
this.emf = emf;
this.typeMapper = mapper;
}
/* (non-Javadoc)
* @see org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmProvider#getEntitySet(org.apache.olingo.commons.api.edm.FullQualifiedName, java.lang.String)
*/
@Override
public CsdlEntitySet getEntitySet(FullQualifiedName entityContainer, String entitySetName) throws ODataException {
if (entityContainer.equals(CONTAINER)) {
EntityType<?> e = emf.getMetamodel()
.getEntities()
.stream()
.filter((ent) -> (ent.getName() + "s")
.equals(entitySetName))
.findFirst()
.orElse(null);
if (e != null) {
CsdlEntitySet entitySet = new CsdlEntitySet();
entitySet
.setName(entitySetName)
.setType(new FullQualifiedName(NAMESPACE, e.getName()));
return entitySet;
}
}
return null;
}
/* (non-Javadoc)
* @see org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmProvider#getEntityContainerInfo(org.apache.olingo.commons.api.edm.FullQualifiedName)
*/
@Override
public CsdlEntityContainerInfo getEntityContainerInfo(FullQualifiedName entityContainerName) throws ODataException {
// This method is invoked when displaying the Service Document at e.g. http://localhost:8080/DemoService/DemoService.svc
if (entityContainerName == null || entityContainerName.equals(CONTAINER)) {
CsdlEntityContainerInfo entityContainerInfo = new CsdlEntityContainerInfo();
entityContainerInfo.setContainerName(CONTAINER);
return entityContainerInfo;
}
return null;
}
/* (non-Javadoc)
* @see org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmProvider#getSchemas()
*/
@Override
public List<CsdlSchema> getSchemas() throws ODataException {
// create Schema
CsdlSchema schema = new CsdlSchema();
schema.setNamespace(NAMESPACE);
// add EntityTypes
List<CsdlEntityType> entityTypes = emf.getMetamodel()
.getEntities()
.stream()
.map((e) -> {
try {
return getEntityType(new FullQualifiedName(NAMESPACE, e.getName()));
} catch (ODataException oe) {
throw new RuntimeException(oe);
}
})
.collect(Collectors.toList());
schema.setEntityTypes(entityTypes);
// add EntityContainer
schema.setEntityContainer(getEntityContainer());
// finally
List<CsdlSchema> schemas = new ArrayList<CsdlSchema>();
schemas.add(schema);
return schemas;
}
/* (non-Javadoc)
* @see org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmProvider#getEntityContainer()
*/
@Override
public CsdlEntityContainer getEntityContainer() throws ODataException {
// add EntityTypes
List<CsdlEntitySet> entitySets = emf.getMetamodel()
.getEntities()
.stream()
.map((e) -> {
try {
// Here we use a simple mapping strategy to map entity types to entity set names:
return getEntitySet(CONTAINER, e.getName() + "s");
} catch (ODataException oe) {
throw new RuntimeException(oe);
}
})
.collect(Collectors.toList());
// create EntityContainer
CsdlEntityContainer entityContainer = new CsdlEntityContainer();
entityContainer.setName(CONTAINER_NAME);
entityContainer.setEntitySets(entitySets);
return entityContainer;
}
@Override
public CsdlEntityType getEntityType(FullQualifiedName entityTypeName) throws ODataException {
CsdlEntityType result = cdslName2Type.get(entityTypeName);
if ( result != null ) {
return result;
}
Metamodel mm = emf.getMetamodel();
result = mm.getEntities()
.stream()
.filter(et -> entityTypeName.equals(new FullQualifiedName(NAMESPACE, et.getName())))
.map(et -> buildODataType(et))
.findFirst()
.orElse(null);
// save for future use
cdslName2Type.put(entityTypeName, result);
return result;
}
/**
* Maps a JPA type to its OData counterpart.
* @param et
* @return
*/
protected CsdlEntityType buildODataType(EntityType<?> et) {
CsdlEntityType result = new CsdlEntityType();
result.setName(et.getName());
// Process simple properties
List<CsdlProperty> properties = et.getDeclaredSingularAttributes()
.stream()
.filter(attr -> attr.getPersistentAttributeType() == PersistentAttributeType.BASIC)
.map(attr -> buildBasicAttribute(et, attr))
.collect(Collectors.toList());
result.setProperties(properties);
// Process Ids
List<CsdlPropertyRef> ids = et.getDeclaredSingularAttributes()
.stream()
.filter(attr -> attr.getPersistentAttributeType() == PersistentAttributeType.BASIC && attr.isId())
.map(attr -> buildRefAttribute(et, attr))
.collect(Collectors.toList());
result.setKey(ids);
// Process 1:N navs
List<CsdlNavigationProperty> navs = et.getDeclaredPluralAttributes()
.stream()
.map(attr -> buildNavAttribute(et, attr))
.collect(Collectors.toList());
result.setNavigationProperties(navs);
// Process N:1 navs
List<CsdlNavigationProperty> navs2 = et.getDeclaredSingularAttributes()
.stream()
.filter(attr -> attr.getPersistentAttributeType() == PersistentAttributeType.MANY_TO_ONE)
.map(attr -> buildNavAttribute(et, attr))
.collect(Collectors.toList());
result.getNavigationProperties().addAll(navs2);
return result;
}
private CsdlProperty buildBasicAttribute(EntityType<?> et, SingularAttribute<?, ?> attr) {
CsdlProperty p = new CsdlProperty().setName(attr.getName())
.setType(typeMapper.java2edm(attr.getJavaType())
.getFullQualifiedName())
.setNullable(et.getDeclaredSingularAttribute(attr.getName())
.isOptional());
return p;
}
private CsdlPropertyRef buildRefAttribute(EntityType<?> et, SingularAttribute<?, ?> attr) {
CsdlPropertyRef p = new CsdlPropertyRef().setName(attr.getName());
return p;
}
// Build NavProperty for 1:N or M:N associations
private CsdlNavigationProperty buildNavAttribute(EntityType<?> et, PluralAttribute<?, ?, ?> attr) {
CsdlNavigationProperty p = new CsdlNavigationProperty().setName(attr.getName())
.setType(new FullQualifiedName(NAMESPACE, attr.getBindableJavaType().getSimpleName()))
.setCollection(true)
.setNullable(false);
return p;
}
// Build NavProperty for N:1 associations
private CsdlNavigationProperty buildNavAttribute(EntityType<?> et, SingularAttribute<?, ?> attr) {
CsdlNavigationProperty p = new CsdlNavigationProperty().setName(attr.getName())
.setType(new FullQualifiedName(NAMESPACE, attr.getBindableJavaType().getSimpleName()))
.setCollection(false)
.setNullable(attr.isOptional());
return p;
}
}

View File

@ -0,0 +1,161 @@
package org.baeldung.examples.olingo4.processor;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.List;
import javax.persistence.EntityManagerFactory;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.SingularAttribute;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.data.ValueType;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.ODataLibraryException;
import org.apache.olingo.server.api.ODataRequest;
import org.apache.olingo.server.api.ODataResponse;
import org.apache.olingo.server.api.ServiceMetadata;
import org.apache.olingo.server.api.processor.CountEntityCollectionProcessor;
import org.apache.olingo.server.api.processor.EntityCollectionProcessor;
import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.serializer.SerializerResult;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriParameter;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
import org.baeldung.examples.olingo4.repository.RepositoryRegistry;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
@Component
public class JpaEntityCollectionProcessor implements CountEntityCollectionProcessor {
private OData odata;
private ServiceMetadata serviceMetadata;
private EntityManagerFactory emf;
private RepositoryRegistry repositoryRegistry;
private JpaEntityMapper entityMapper;
public JpaEntityCollectionProcessor(EntityManagerFactory emf, RepositoryRegistry repositoryRegistry, JpaEntityMapper entityMapper) {
this.emf = emf;
this.repositoryRegistry = repositoryRegistry;
this.entityMapper = entityMapper;
}
@Override
public void init(OData odata, ServiceMetadata serviceMetadata) {
this.odata = odata;
this.serviceMetadata = serviceMetadata;
}
@Override
public void readEntityCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType responseFormat) throws ODataApplicationException, ODataLibraryException {
// 1st we have retrieve the requested EntitySet from the uriInfo object (representation of the parsed service URI)
List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0); // in our example, the first segment is the EntitySet
EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
// 2nd: fetch the data from backend for this requested EntitySetName
// it has to be delivered as EntitySet object
EntityCollection entitySet = getData(edmEntitySet, uriInfo);
// 3rd: create a serializer based on the requested format (json)
ODataSerializer serializer = odata.createSerializer(responseFormat);
// 4th: Now serialize the content: transform from the EntitySet object to InputStream
EdmEntityType edmEntityType = edmEntitySet.getEntityType();
ContextURL contextUrl = ContextURL.with()
.entitySet(edmEntitySet)
.build();
final String id = request.getRawBaseUri() + "/" + edmEntitySet.getName();
EntityCollectionSerializerOptions opts = EntityCollectionSerializerOptions.with()
.id(id)
.contextURL(contextUrl)
.build();
SerializerResult serializerResult = serializer.entityCollection(serviceMetadata, edmEntityType, entitySet, opts);
InputStream serializedContent = serializerResult.getContent();
// Finally: configure the response object: set the body, headers and status code
response.setContent(serializedContent);
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
}
@Override
public void countEntityCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo) throws ODataApplicationException, ODataLibraryException {
// 1st we have retrieve the requested EntitySet from the uriInfo object (representation of the parsed service URI)
List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0); // in our example, the first segment is the EntitySet
EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
// 2nd: fetch the data from backend for this requested EntitySetName
Long count = getCount(edmEntitySet, uriInfo);
// Finally: configure the response object: set the body, headers and status code
response.setContent(new ByteArrayInputStream(count.toString().getBytes()));
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
response.setHeader(HttpHeader.CONTENT_TYPE, "text/plain");
}
/**
* Helper method to retrieve all entities of an entity set from an the backend database
* @param edmEntitySet
* @param uriInfo
* @return
*/
protected EntityCollection getData(EdmEntitySet edmEntitySet, UriInfo uriInfo) {
EdmEntityType type = edmEntitySet.getEntityType();
JpaRepository<?, ?> repo = (JpaRepository<?, ?>)repositoryRegistry.getRepositoryForEntity(type);
EntityCollection result = new EntityCollection();
repo.findAll()
.stream()
.forEach((it) -> result.getEntities()
.add(entityMapper.map2entity(edmEntitySet, it)));
return result;
}
/**
* Helper method to get the total size of an entity set
* @param edmEntitySet
* @param uriInfo
* @return
*/
protected Long getCount(EdmEntitySet edmEntitySet, UriInfo uriInfo) {
EdmEntityType type = edmEntitySet.getEntityType();
JpaRepository<?, ?> repo = (JpaRepository<?, ?>)repositoryRegistry.getRepositoryForEntity(type);
EntityCollection result = new EntityCollection();
return repo.count();
}
}

View File

@ -0,0 +1,93 @@
/**
*
*/
package org.baeldung.examples.olingo4.processor;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;
import javax.persistence.EntityManagerFactory;
import javax.persistence.metamodel.EntityType;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.data.ValueType;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
import org.springframework.stereotype.Component;
/**
* <p>Helper class that converts a JPA entity into an OData entity using
* available metadata from the JPA's EntityManagerFactory.</p>
*
* @author Philippe
*
*/
@Component
public class JpaEntityMapper {
private EntityManagerFactory emf;
public JpaEntityMapper(EntityManagerFactory emf) {
this.emf = emf;
}
public Entity map2entity(EdmEntitySet edmEntitySet, Object entry) {
EntityType<?> et = emf.getMetamodel()
.entity(entry.getClass());
Entity e = new Entity();
try {
et.getDeclaredSingularAttributes().stream()
.forEach( (attr) -> {
if ( !attr.isAssociation()) {
Object v = getPropertyValue(entry,attr.getName());
Property p = new Property(null, attr.getName(),ValueType.PRIMITIVE,v);
e.addProperty(p);
if ( attr.isId()) {
e.setId(createId(edmEntitySet.getName(),v));
}
}
});
} catch (Exception ex) {
throw new ODataRuntimeException("[E141] Unable to create OData entity", ex);
}
return e;
}
public Object getPropertyValue(Object entry, String name) {
try {
return PropertyUtils.getProperty(entry,name);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new ODataRuntimeException("[E141] Unable to read property from entity, property=" + name, e);
}
}
public void setPropertyValue(Object entry, String name,Object value) {
try {
PropertyUtils.setProperty(entry,name,value);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new ODataRuntimeException("[E141] Unable to read property from entity, property=" + name, e);
}
}
private URI createId(String entitySetName, Object id) {
try {
return new URI(entitySetName + "(" + String.valueOf(id) + ")");
} catch (URISyntaxException e) {
throw new ODataRuntimeException("[E177] Unable to create URI", e);
}
}
}

View File

@ -0,0 +1,304 @@
/**
*
*/
package org.baeldung.examples.olingo4.processor;
import java.io.InputStream;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.metamodel.SingularAttribute;
import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.ODataLibraryException;
import org.apache.olingo.server.api.ODataRequest;
import org.apache.olingo.server.api.ODataResponse;
import org.apache.olingo.server.api.ServiceMetadata;
import org.apache.olingo.server.api.processor.EntityProcessor;
import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.serializer.SerializerResult;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriParameter;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
import org.apache.olingo.server.api.uri.UriResourceNavigation;
import org.baeldung.examples.olingo4.repository.EdmEntityRepository;
import org.baeldung.examples.olingo4.repository.RepositoryRegistry;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
/**
* JpaEntityProcessor adapter.
* <p>This implementation is heavily based on the Tutorial available
* at Olingo's site. It is meant to be an starting point for an actual implementation.</p>
* <p>Please note that many features from a full-fledged are missing
* @author Philippe
*
*/
@Component
public class JpaEntityProcessor implements EntityProcessor {
private EntityManagerFactory emf;
private OData odata;
private ServiceMetadata serviceMetadata;
private RepositoryRegistry registry;
private JpaEntityMapper entityMapper;
public JpaEntityProcessor(EntityManagerFactory emf, RepositoryRegistry registry, JpaEntityMapper entityMapper) {
this.emf = emf;
this.registry = registry;
this.entityMapper = entityMapper;
}
/* (non-Javadoc)
* @see org.apache.olingo.server.api.processor.Processor#init(org.apache.olingo.server.api.OData, org.apache.olingo.server.api.ServiceMetadata)
*/
@Override
public void init(OData odata, ServiceMetadata serviceMetadata) {
this.odata = odata;
this.serviceMetadata = serviceMetadata;
}
/* (non-Javadoc)
* @see org.apache.olingo.server.api.processor.EntityProcessor#readEntity(org.apache.olingo.server.api.ODataRequest, org.apache.olingo.server.api.ODataResponse, org.apache.olingo.server.api.uri.UriInfo, org.apache.olingo.commons.api.format.ContentType)
*/
@Override
public void readEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType responseFormat) throws ODataApplicationException, ODataLibraryException {
// First, we have to figure out which entity is requested
List<UriResource> resourceParts = uriInfo.getUriResourceParts();
InputStream entityStream;
UriResourceEntitySet rootResourceEntitySet = (UriResourceEntitySet) resourceParts.get(0);
EdmEntitySet rootEntitySet = rootResourceEntitySet.getEntitySet();
List<UriParameter> rootPredicates = rootResourceEntitySet.getKeyPredicates();
if ( resourceParts.size() == 1 ) {
entityStream = readRootEntity(rootEntitySet,rootPredicates,responseFormat);
}
else if ( resourceParts.size() == 2 ) {
UriResource part = resourceParts.get(1);
if ( !(part instanceof UriResourceNavigation)) {
throw new ODataRuntimeException("[E103] part type not supported: class=" + part.getClass().getName());
}
UriResourceNavigation navSegment = (UriResourceNavigation)part;
entityStream = readRelatedEntity(request, rootEntitySet,rootPredicates,navSegment.getProperty(),navSegment.getKeyPredicates(),responseFormat);
}
else {
// For now, we'll only allow navigation just to directly linked navs
throw new ODataApplicationException("[E109] Multi-level navigation not supported", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
//4. configure the response object
response.setContent(entityStream);
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
}
// Lookup the EntitySet associated with an EntityType
// In our example, we assume we have only one entityset for each entity type
private EdmEntitySet entitySetFromType(EdmEntityType type) {
return serviceMetadata
.getEdm()
.getEntityContainer()
.getEntitySets()
.stream()
.filter((s) -> s.getEntityType().getName().equals(type.getName()))
.findFirst()
.orElseThrow(() -> new ODataRuntimeException("[E144] No entity set found for type " + type.getFullQualifiedName()));
}
//
// private boolean isOne2ManyProperty(EdmEntityType entityType, EdmNavigationProperty property) {
// return entityType.getProperty(property.getName()) != null && property.isCollection();
//}
@SuppressWarnings({ "rawtypes", "unchecked" })
private InputStream readRootEntity(EdmEntitySet entitySet, List<UriParameter> keyPredicates,ContentType responseFormat) throws ODataApplicationException, ODataLibraryException {
EdmEntityType type = entitySet.getEntityType();
JpaRepository repo = registry.getRepositoryForEntity(type);
// Get key value
Long keyValue = getEntityKey(keyPredicates);
Optional<Object> entry = repo.findById(keyValue);
if ( !entry.isPresent()) {
throw new ODataApplicationException(
"[E116] NO entity found for the given key",
HttpStatusCode.NOT_FOUND.getStatusCode(),
Locale.ENGLISH);
}
Entity e = entityMapper.map2entity(entitySet, entry.get());
return serializeEntity(entitySet,e,responseFormat);
}
private InputStream serializeEntity(EdmEntitySet entitySet, Entity entity,ContentType responseFormat) throws ODataApplicationException, ODataLibraryException {
ContextURL contextUrl = ContextURL.with().entitySet(entitySet).build();
// expand and select currently not supported
EntitySerializerOptions options = EntitySerializerOptions
.with()
.contextURL(contextUrl)
.build();
ODataSerializer serializer = odata.createSerializer(responseFormat);
SerializerResult serializerResult = serializer.entity(serviceMetadata, entitySet.getEntityType(), entity, options);
return serializerResult.getContent();
}
// @SuppressWarnings("unchecked")
// protected InputStream readRelatedEntities(EdmEntitySet rootEntitySet, List<UriParameter> rootPredicates, EdmNavigationProperty property, ContentType responseFormat) throws ODataApplicationException {
//
// Object jpaEntity = readJPAEntity(rootEntitySet, rootPredicates);
// try {
// Collection<Object> set = (Collection<Object>)PropertyUtils.getProperty(jpaEntity, property.getName());
// EdmEntitySet entitySet = entitySetFromType(property.getType());
// ContextURL contextUrl = ContextURL
// .with()
// .entitySet(entitySet)
// .build();
//
// EntityCollectionSerializerOptions options = EntityCollectionSerializerOptions
// .with()
// .contextURL(contextUrl)
// .build();
//
// EntityCollection result = new EntityCollection();
//
// set.stream()
// .map((o) -> this.entityMapper.map2entity(entitySet, o))
// .forEach((e) -> result.getEntities().add(e));
//
// ODataSerializer serializer = odata.createSerializer(responseFormat);
// SerializerResult serializerResult = serializer.entityCollection(serviceMetadata, property.getType(), result, options);
// return serializerResult.getContent();
// }
// catch(Exception ex) {
// throw new ODataRuntimeException("[E181] Error accessing database", ex);
// }
// }
@SuppressWarnings({ "rawtypes", "unchecked" })
private InputStream readRelatedEntity(ODataRequest request, EdmEntitySet entitySet, List<UriParameter> rootPredicates, EdmNavigationProperty property, List<UriParameter> parentPredicates, ContentType responseFormat) throws ODataApplicationException, ODataLibraryException {
JpaRepository<Object,Object> repo = (JpaRepository<Object,Object>)registry.getRepositoryForEntity(entitySet.getEntityType());
EdmEntityRepository<Object> relatedRepo = (EdmEntityRepository<Object>)registry.getRepositoryForEntity(property.getType());
// We assume here that we have a bi-directional 1:N relationship, so we'll
// always have a property in the child entity that points to the parent
Class<?> rootClass = ((EdmEntityRepository)repo).getEntityClass();
Class<?> relatedClass = ((EdmEntityRepository)relatedRepo).getEntityClass();
SingularAttribute fk = emf.getMetamodel()
.entity(rootClass)
.getSingularAttributes()
.stream()
.filter((attr) -> {
boolean b = attr.isAssociation() && attr.getJavaType().isAssignableFrom(relatedClass);
return b;
})
.findFirst()
.orElse(null);
if ( fk == null ) {
throw new ODataRuntimeException("[E230] No singular attribute of child class '" + relatedClass.getName() + "' found" );
}
Long pkValue = getEntityKey(rootPredicates);
EntityManager em = this.emf.createEntityManager();
try {
// Read data from DB
Object root = em.find(rootClass, pkValue);
Object related = this.entityMapper.getPropertyValue(root, fk.getName());
EdmEntitySet relatedEntitySet = entitySetFromType(property.getType());
Entity e = entityMapper.map2entity(relatedEntitySet, related);
return serializeEntity(relatedEntitySet,e,responseFormat);
}
finally {
em.close();
}
}
// @SuppressWarnings("unchecked")
// private Object readJPAEntity(EdmEntitySet edmEntitySet, List<UriParameter> keyPredicates) throws ODataApplicationException {
// EdmEntityType type = edmEntitySet.getEntityType();
// JpaRepository<Object,Object> repo = (JpaRepository<Object,Object>)registry.getRepositoryForEntity(type);
//
// // Get key value
// Object keyValue = getEntityKey(type,keyPredicates);
// Object entry = repo
// .findById(keyValue)
// .orElseThrow(
// () -> new ODataApplicationException("[E116] NO entity found for the given key",
// HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH));
//
// return entry;
// }
private Long getEntityKey(List<UriParameter> keyPredicates) {
if ( keyPredicates.size() > 1 ) {
throw new ODataRuntimeException("[E131] Composite keys are not supported");
}
// For now, we'll assume we only have numeric keys.
UriParameter keyParam = keyPredicates.get(0);
try {
return Long.parseLong(keyParam.getText());
}
catch(NumberFormatException nfe) {
throw new ODataRuntimeException("[E140] Invalid key value. Only numeric keys are supported by this service");
}
}
/* (non-Javadoc)
* @see org.apache.olingo.server.api.processor.EntityProcessor#createEntity(org.apache.olingo.server.api.ODataRequest, org.apache.olingo.server.api.ODataResponse, org.apache.olingo.server.api.uri.UriInfo, org.apache.olingo.commons.api.format.ContentType, org.apache.olingo.commons.api.format.ContentType)
*/
@Override
public void createEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat, ContentType responseFormat) throws ODataApplicationException, ODataLibraryException {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see org.apache.olingo.server.api.processor.EntityProcessor#updateEntity(org.apache.olingo.server.api.ODataRequest, org.apache.olingo.server.api.ODataResponse, org.apache.olingo.server.api.uri.UriInfo, org.apache.olingo.commons.api.format.ContentType, org.apache.olingo.commons.api.format.ContentType)
*/
@Override
public void updateEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat, ContentType responseFormat) throws ODataApplicationException, ODataLibraryException {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see org.apache.olingo.server.api.processor.EntityProcessor#deleteEntity(org.apache.olingo.server.api.ODataRequest, org.apache.olingo.server.api.ODataResponse, org.apache.olingo.server.api.uri.UriInfo)
*/
@Override
public void deleteEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo) throws ODataApplicationException, ODataLibraryException {
// TODO Auto-generated method stub
}
}

View File

@ -0,0 +1,16 @@
package org.baeldung.examples.olingo4.repository;
import org.baeldung.examples.olingo4.domain.CarMaker;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
@Repository
public interface CarMakerRepository extends EdmEntityRepository<CarMaker>, JpaRepository<CarMaker, Long>, JpaSpecificationExecutor<CarMaker> {
public default String getEdmEntityName() { return CarMaker.class.getSimpleName();}
@Override
default Class<CarMaker> getEntityClass() {
return CarMaker.class;
}
}

View File

@ -0,0 +1,22 @@
package org.baeldung.examples.olingo4.repository;
import java.util.List;
import org.baeldung.examples.olingo4.domain.CarModel;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
@Repository
public interface CarModelRepository extends EdmEntityRepository<CarModel>, JpaRepository<CarModel, Long>, JpaSpecificationExecutor<CarModel> {
public List<CarModel> findByMakerId(Long makerId);
public default String getEdmEntityName() { return CarModel.class.getSimpleName();}
@Override
default Class<CarModel> getEntityClass() {
return CarModel.class;
}
}

View File

@ -0,0 +1,17 @@
/**
*
*/
package org.baeldung.examples.olingo4.repository;
/**
* @author Philippe
*
*/
public interface EdmEntityRepository<E> {
public String getEdmEntityName();
public Class<E> getEntityClass();
}

View File

@ -0,0 +1,29 @@
package org.baeldung.examples.olingo4.repository;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
@Component
public class RepositoryRegistry {
private Map<String,JpaRepository<?,?>> repositoriesByClassName = new HashMap<>();
public RepositoryRegistry(List<EdmEntityRepository<?>> allRepositories) {
allRepositories.stream()
.forEach((r) ->
repositoriesByClassName.put(r.getEdmEntityName(),(JpaRepository<?,?>)r));
}
public JpaRepository<?,?> getRepositoryForEntity(EdmEntityType entityType) {
JpaRepository<?,?> repo = repositoriesByClassName.get(entityType.getName());
return repo;
}
}

View File

@ -0,0 +1,9 @@
server:
port: 8080
spring:
jpa:
show-sql: true
open-in-view: true
hibernate:
ddl-auto: update

View File

@ -0,0 +1,12 @@
insert into car_maker(id,name) values (1,'Special Motors');
insert into car_maker(id,name) values (2,'BWM');
insert into car_maker(id,name) values (3,'Dolores');
insert into car_model(id,maker_fk,name,sku,year) values(1,1,'Muze','SM001',2018);
insert into car_model(id,maker_fk,name,sku,year) values(2,1,'Empada','SM002',2008);
insert into car_model(id,maker_fk,name,sku,year) values(4,2,'BWM-100','BWM100',2008);
insert into car_model(id,maker_fk,name,sku,year) values(5,2,'BWM-200','BWM200',2009);
insert into car_model(id,maker_fk,name,sku,year) values(6,2,'BWM-300','BWM300',2008);
alter sequence hibernate_sequence restart with 100;

View File

@ -0,0 +1,16 @@
package org.baeldung.examples.olingo4;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class Olingo4SampleApplicationTests {
@Test
public void contextLoads() {
}
}

View File

@ -0,0 +1,21 @@
package com.baeldung.localization;
import java.text.ParseException;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
public class App {
/**
* Runs all available formatter
* @throws ParseException
*/
public static void main(String[] args) {
List<Locale> locales = Arrays.asList(new Locale[] { Locale.UK, Locale.ITALY, Locale.FRANCE, Locale.forLanguageTag("pl-PL") });
Localization.run(locales);
JavaSEFormat.run(locales);
ICUFormat.run(locales);
}
}

View File

@ -0,0 +1,29 @@
package com.baeldung.localization;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import com.ibm.icu.text.MessageFormat;
public class ICUFormat {
public static String getLabel(Locale locale, Object[] data) {
ResourceBundle bundle = ResourceBundle.getBundle("formats", locale);
String format = bundle.getString("label-icu");
MessageFormat formatter = new MessageFormat(format, locale);
return formatter.format(data);
}
public static void run(List<Locale> locales) {
System.out.println("ICU formatter");
locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { "Alice", "female", 0 })));
locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { "Alice", "female", 1 })));
locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { "Alice", "female", 2 })));
locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { "Alice", "female", 3 })));
locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { "Bob", "male", 0 })));
locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { "Bob", "male", 1 })));
locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { "Bob", "male", 2 })));
locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { "Bob", "male", 3 })));
}
}

View File

@ -0,0 +1,24 @@
package com.baeldung.localization;
import java.text.MessageFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
public class JavaSEFormat {
public static String getLabel(Locale locale, Object[] data) {
ResourceBundle bundle = ResourceBundle.getBundle("formats", locale);
final String pattern = bundle.getString("label");
final MessageFormat formatter = new MessageFormat(pattern, locale);
return formatter.format(data);
}
public static void run(List<Locale> locales) {
System.out.println("Java formatter");
final Date date = new Date(System.currentTimeMillis());
locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { date, "Alice", 0 })));
locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { date, "Alice", 2 })));
}
}

View File

@ -0,0 +1,18 @@
package com.baeldung.localization;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
public class Localization {
public static String getLabel(Locale locale) {
final ResourceBundle bundle = ResourceBundle.getBundle("messages", locale);
return bundle.getString("label");
}
public static void run(List<Locale> locales) {
locales.forEach(locale -> System.out.println(getLabel(locale)));
}
}

View File

@ -0,0 +1,2 @@
label=On {0, date, short} {1} has sent you {2, choice, 0#no messages|1#a message|2#two messages|2<{2,number,integer} messages}.
label-icu={0} has sent you {2, plural, =0 {no messages} =1 {a message} other {{2, number, integer} messages}}.

View File

@ -0,0 +1,2 @@
label={0, date, short}, {1}{2, choice, 0# ne|0<} vous a envoy\u00e9 {2, choice, 0#aucun message|1#un message|2#deux messages|2<{2,number,integer} messages}.
label-icu={0} {2, plural, =0 {ne } other {}}vous a envoy\u00e9 {2, plural, =0 {aucun message} =1 {un message} other {{2, number, integer} messages}}.

View File

@ -0,0 +1,2 @@
label={0, date, short} {1} ti ha inviato {2, choice, 0#nessun messagio|1#un messaggio|2#due messaggi|2<{2, number, integer} messaggi}.
label-icu={0} {2, plural, =0 {non } other {}}ti ha inviato {2, plural, =0 {nessun messaggio} =1 {un messaggio} other {{2, number, integer} messaggi}}.

View File

@ -0,0 +1,2 @@
label=W {0, date, short} {1}{2, choice, 0# nie|0<} wys\u0142a\u0142a ci {2, choice, 0#\u017Cadnych wiadomo\u015Bci|1#wiadomo\u015B\u0107|2#dwie wiadomo\u015Bci|2<{2, number, integer} wiadomo\u015Bci}.
label-icu={0} {2, plural, =0 {nie } other {}}{1, select, male {wys\u0142a\u0142} female {wys\u0142a\u0142a} other {wys\u0142a\u0142o}} ci {2, plural, =0 {\u017Cadnej wiadomo\u015Bci} =1 {wiadomo\u015B\u0107} other {{2, number, integer} wiadomo\u015Bci}}.

View File

@ -0,0 +1 @@
label=Alice has sent you a message.

View File

@ -0,0 +1 @@
label=Alice vous a envoy\u00e9 un message.

View File

@ -0,0 +1 @@
label=Alice ti ha inviato un messaggio.

View File

@ -0,0 +1 @@
label=Alice wys\u0142a\u0142a ci wiadomo\u015B\u0107.

View File

@ -0,0 +1,74 @@
package com.baeldung.localization;
import static org.junit.Assert.assertEquals;
import java.util.Locale;
import org.junit.Test;
import com.baeldung.localization.ICUFormat;
public class ICUFormatUnitTest {
@Test
public void givenInUK_whenAliceSendsNothing_thenCorrectMessage() {
assertEquals("Alice has sent you no messages.", ICUFormat.getLabel(Locale.UK, new Object[] { "Alice", "female", 0 }));
}
@Test
public void givenInUK_whenAliceSendsOneMessage_thenCorrectMessage() {
assertEquals("Alice has sent you a message.", ICUFormat.getLabel(Locale.UK, new Object[] { "Alice", "female", 1 }));
}
@Test
public void givenInUK_whenBobSendsSixMessages_thenCorrectMessage() {
assertEquals("Bob has sent you 6 messages.", ICUFormat.getLabel(Locale.UK, new Object[] { "Bob", "male", 6 }));
}
@Test
public void givenInItaly_whenAliceSendsNothing_thenCorrectMessage() {
assertEquals("Alice non ti ha inviato nessun messaggio.", ICUFormat.getLabel(Locale.ITALY, new Object[] { "Alice", "female", 0 }));
}
@Test
public void givenInItaly_whenAliceSendsOneMessage_thenCorrectMessage() {
assertEquals("Alice ti ha inviato un messaggio.", ICUFormat.getLabel(Locale.ITALY, new Object[] { "Alice", "female", 1 }));
}
@Test
public void givenInItaly_whenBobSendsSixMessages_thenCorrectMessage() {
assertEquals("Bob ti ha inviato 6 messaggi.", ICUFormat.getLabel(Locale.ITALY, new Object[] { "Bob", "male", 6 }));
}
@Test
public void givenInFrance_whenAliceSendsNothing_thenCorrectMessage() {
assertEquals("Alice ne vous a envoyé aucun message.", ICUFormat.getLabel(Locale.FRANCE, new Object[] { "Alice", "female", 0 }));
}
@Test
public void givenInFrance_whenAliceSendsOneMessage_thenCorrectMessage() {
assertEquals("Alice vous a envoyé un message.", ICUFormat.getLabel(Locale.FRANCE, new Object[] { "Alice", "female", 1 }));
}
@Test
public void givenInFrance_whenBobSendsSixMessages_thenCorrectMessage() {
assertEquals("Bob vous a envoyé 6 messages.", ICUFormat.getLabel(Locale.FRANCE, new Object[] { "Bob", "male", 6 }));
}
@Test
public void givenInPoland_whenAliceSendsNothing_thenCorrectMessage() {
assertEquals("Alice nie wysłała ci żadnej wiadomości.", ICUFormat.getLabel(Locale.forLanguageTag("pl-PL"), new Object[] { "Alice", "female", 0 }));
}
@Test
public void givenInPoland_whenAliceSendsOneMessage_thenCorrectMessage() {
assertEquals("Alice wysłała ci wiadomość.", ICUFormat.getLabel(Locale.forLanguageTag("pl-PL"), new Object[] { "Alice", "female", 1 }));
}
@Test
public void givenInPoland_whenBobSendsSixMessages_thenCorrectMessage() {
assertEquals("Bob wysłał ci 6 wiadomości.", ICUFormat.getLabel(Locale.forLanguageTag("pl-PL"), new Object[] { "Bob", "male", 6 }));
}
}

View File

@ -0,0 +1,28 @@
package com.baeldung.singleton;
public class Car {
private String type;
private String model;
private boolean serviced = false;
public Car(String type, String model) {
super();
this.type = type;
this.model = model;
}
public boolean isServiced () {
return serviced;
}
public void setServiced(Boolean serviced) {
this.serviced = serviced;
}
@Override
public String toString() {
return "Car [type=" + type + ", model=" + model + "]";
}
}

View File

@ -0,0 +1,23 @@
package com.baeldung.singleton;
import java.util.UUID;
import javax.enterprise.context.Dependent;
import org.springframework.web.context.annotation.RequestScope;
@RequestScope
public class CarServiceBean {
private UUID id = UUID.randomUUID();
public UUID getId() {
return this.id;
}
@Override
public String toString() {
return "CarService [id=" + id + "]";
}
}

View File

@ -0,0 +1,46 @@
package com.baeldung.singleton;
import java.util.UUID;
import javax.ejb.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class CarServiceEjbSingleton {
private static Logger LOG = LoggerFactory.getLogger(CarServiceEjbSingleton.class);
private UUID id = UUID.randomUUID();
private static int serviceQueue;
public UUID getId() {
return this.id;
}
@Override
public String toString() {
return "CarServiceEjbSingleton [id=" + id + "]";
}
public int service(Car car) {
serviceQueue++;
LOG.info("Car {} is being serviced @ CarServiceEjbSingleton - serviceQueue: {}", car, serviceQueue);
simulateService(car);
serviceQueue--;
LOG.info("Car service for {} is completed - serviceQueue: {}", car, serviceQueue);
return serviceQueue;
}
private void simulateService(Car car) {
try {
Thread.sleep(100);
car.setServiced(true);
} catch (InterruptedException e) {
LOG.error("CarServiceEjbSingleton::InterruptedException: {}", e);
}
}
}

View File

@ -0,0 +1,47 @@
package com.baeldung.singleton;
import java.util.UUID;
import javax.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class CarServiceSingleton {
private static Logger LOG = LoggerFactory.getLogger(CarServiceSingleton.class);
private UUID id = UUID.randomUUID();
private static int serviceQueue;
public UUID getId() {
return this.id;
}
@Override
public String toString() {
return "CarServiceSingleton [id=" + id + "]";
}
public int service(Car car) {
serviceQueue++;
LOG.info("Car {} is being serviced @ CarServiceSingleton - serviceQueue: {}", car, serviceQueue);
simulateService(car);
serviceQueue--;
LOG.info("Car service for {} is completed - serviceQueue: {}", car, serviceQueue);
return serviceQueue;
}
private void simulateService(Car car) {
try {
Thread.sleep(100);
car.setServiced(true);
} catch (InterruptedException e) {
LOG.error("CarServiceSingleton::InterruptedException: {}", e);
}
}
}

View File

@ -0,0 +1,142 @@
package com.baeldung.singleton;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.ejb.EJB;
import javax.inject.Inject;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RunWith(Arquillian.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class CarServiceIntegrationTest {
public static final Logger LOG = LoggerFactory.getLogger(CarServiceIntegrationTest.class);
@Deployment
public static JavaArchive createDeployment() {
return ShrinkWrap.create(JavaArchive.class)
.addClasses(CarServiceBean.class, CarServiceSingleton.class, CarServiceEjbSingleton.class, Car.class)
.addAsResource("META-INF/persistence.xml")
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}
@Inject
private CarServiceBean carServiceBean;
@Inject
private CarServiceSingleton carServiceSingleton;
@EJB
private CarServiceEjbSingleton carServiceEjbSingleton;
private static Map<String, UUID> idMap = new HashMap<>();
@Before
public void setUp() {
// populate idMap only on first run
if (idMap.isEmpty()) {
LOG.info("setUp::carServiceBean: {}", carServiceBean.getId());
idMap.put("carServiceBeanId", carServiceBean.getId());
LOG.info("setUp::carServiceSingleton: {}", carServiceSingleton.getId());
idMap.put("carServiceSingletonId", carServiceSingleton.getId());
LOG.info("setUp::carServiceEjbSingleton: {}", carServiceEjbSingleton.getId());
idMap.put("carServiceEjbSingletonId", carServiceEjbSingleton.getId());
}
}
@Test
public void givenRun1_whenGetId_thenSingletonIdEqual() {
int testRun = 1;
assertNotNull(carServiceBean);
assertNotNull(carServiceSingleton);
assertNotNull(carServiceEjbSingleton);
UUID carServiceBeanId = carServiceBean.getId();
assertEquals(idMap.get("carServiceBeanId"), carServiceBeanId);
LOG.info("Test run {}::carServiceBeanId: {}", testRun, carServiceBeanId);
UUID carServiceSingletonId = carServiceSingleton.getId();
assertEquals(idMap.get("carServiceSingletonId"), carServiceSingletonId);
LOG.info("Test run {}::carServiceSingletonId: {}", testRun, carServiceSingletonId);
UUID carServiceEjbSingletonId = carServiceEjbSingleton.getId();
assertEquals(idMap.get("carServiceEjbSingletonId"), carServiceEjbSingletonId);
LOG.info("Test run {}::carServiceEjbSingletonId: {}", testRun, carServiceEjbSingletonId);
}
@Test
public void givenRun2_whenGetId_thenSingletonIdEqual() {
int testRun = 2;
assertNotNull(carServiceBean);
assertNotNull(carServiceSingleton);
assertNotNull(carServiceEjbSingleton);
UUID carServiceBeanId = carServiceBean.getId();
assertNotEquals(idMap.get("carServiceBeanId"), carServiceBeanId);
LOG.info("Test run {}::carServiceBeanId: {}", testRun, carServiceBeanId);
UUID carServiceSingletonId = carServiceSingleton.getId();
assertEquals(idMap.get("carServiceSingletonId"), carServiceSingletonId);
LOG.info("Test run {}::carServiceSingletonId: {}", testRun, carServiceSingletonId);
UUID carServiceEjbSingletonId = carServiceEjbSingleton.getId();
assertEquals(idMap.get("carServiceEjbSingletonId"), carServiceEjbSingletonId);
LOG.info("Test run {}::carServiceEjbSingletonId: {}", testRun, carServiceEjbSingletonId);
}
@Test
public void givenRun3_whenSingleton_thenNoLocking() {
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
String model = Double.toString(Math.round(Math.random() * 100));
Car car = new Car("Speedster", model);
int serviceQueue = carServiceSingleton.service(car);
assertTrue(serviceQueue < 10);
}
}).start();
}
return;
}
@Test
public void givenRun4_whenEjb_thenLocking() {
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
String model = Double.toString(Math.round(Math.random() * 100));
Car car = new Car("Speedster", model);
int serviceQueue = carServiceEjbSingleton.service(car);
assertEquals(0, serviceQueue);
}
}).start();
}
return;
}
}

View File

@ -7,6 +7,7 @@ version '1.0-SNAPSHOT'
buildscript {
ext.kotlin_version = '1.2.41'
ext.ktor_version = '0.9.2'
ext.khttp_version = '0.1.0'
repositories {
mavenCentral()
@ -47,8 +48,13 @@ dependencies {
compile "io.ktor:ktor-server-netty:$ktor_version"
compile "ch.qos.logback:logback-classic:1.2.1"
compile "io.ktor:ktor-gson:$ktor_version"
compile "khttp:khttp:$khttp_version"
testCompile group: 'junit', name: 'junit', version: '4.12'
testCompile group: 'org.jetbrains.spek', name: 'spek-api', version: '1.1.5'
testCompile group: 'org.jetbrains.spek', name: 'spek-subject-extension', version: '1.1.5'
testCompile group: 'org.jetbrains.spek', name: 'spek-junit-platform-engine', version: '1.1.5'
implementation 'com.beust:klaxon:3.0.1'
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
}
task runServer(type: JavaExec) {

View File

@ -166,6 +166,12 @@
<version>2.6</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.reactivex.rxjava2</groupId>
<artifactId>rxkotlin</artifactId>
<version>2.3.0</version>
</dependency>
</dependencies>
<properties>

View File

@ -0,0 +1,157 @@
package com.baeldung.kotlin.rxkotlin
import io.reactivex.Maybe
import io.reactivex.Observable
import io.reactivex.functions.BiFunction
import io.reactivex.rxkotlin.*
import io.reactivex.subjects.PublishSubject
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
class RxKotlinTest {
@Test
fun whenBooleanArrayToObserver_thenBooleanObserver() {
val observable = listOf(true, false, false).toObservable()
observable.test().assertValues(true, false, false)
}
@Test
fun whenBooleanArrayToFlowable_thenBooleanFlowable() {
val flowable = listOf(true, false, false).toFlowable()
flowable.buffer(2).test().assertValues(listOf(true, false), listOf(false))
}
@Test
fun whenIntArrayToObserver_thenIntObserver() {
val observable = listOf(1, 1, 2, 3).toObservable()
observable.test().assertValues(1, 1, 2, 3)
}
@Test
fun whenIntArrayToFlowable_thenIntFlowable() {
val flowable = listOf(1, 1, 2, 3).toFlowable()
flowable.buffer(2).test().assertValues(listOf(1, 1), listOf(2, 3))
}
@Test
fun whenObservablePairToMap_thenSingleNoDuplicates() {
val list = listOf(Pair("a", 1), Pair("b", 2), Pair("c", 3), Pair("a", 4))
val observable = list.toObservable()
val map = observable.toMap()
assertEquals(mapOf(Pair("a", 4), Pair("b", 2), Pair("c", 3)), map.blockingGet())
}
@Test
fun whenObservablePairToMap_thenSingleWithDuplicates() {
val list = listOf(Pair("a", 1), Pair("b", 2), Pair("c", 3), Pair("a", 4))
val observable = list.toObservable()
val map = observable.toMultimap()
assertEquals(
mapOf(Pair("a", listOf(1, 4)), Pair("b", listOf(2)), Pair("c", listOf(3))),
map.blockingGet())
}
@Test
fun whenMergeAll_thenStream() {
val subject = PublishSubject.create<Observable<String>>()
val observable = subject.mergeAll()
val testObserver = observable.test()
subject.onNext(Observable.just("first", "second"))
testObserver.assertValues("first", "second")
subject.onNext(Observable.just("third", "fourth"))
subject.onNext(Observable.just("fifth"))
testObserver.assertValues("first", "second", "third", "fourth", "fifth")
}
@Test
fun whenConcatAll_thenStream() {
val subject = PublishSubject.create<Observable<String>>()
val observable = subject.concatAll()
val testObserver = observable.test()
subject.onNext(Observable.just("first", "second"))
testObserver.assertValues("first", "second")
subject.onNext(Observable.just("third", "fourth"))
subject.onNext(Observable.just("fifth"))
testObserver.assertValues("first", "second", "third", "fourth", "fifth")
}
@Test
fun whenSwitchLatest_thenStream() {
val subject = PublishSubject.create<Observable<String>>()
val observable = subject.switchLatest()
val testObserver = observable.test()
subject.onNext(Observable.just("first", "second"))
testObserver.assertValues("first", "second")
subject.onNext(Observable.just("third", "fourth"))
subject.onNext(Observable.just("fifth"))
testObserver.assertValues("first", "second", "third", "fourth", "fifth")
}
@Test
fun whenMergeAllMaybes_thenObservable() {
val subject = PublishSubject.create<Maybe<Int>>()
val observable = subject.mergeAllMaybes()
val testObserver = observable.test()
subject.onNext(Maybe.just(1))
subject.onNext(Maybe.just(2))
subject.onNext(Maybe.empty())
testObserver.assertValues(1, 2)
subject.onNext(Maybe.error(Exception("")))
subject.onNext(Maybe.just(3))
testObserver.assertValues(1, 2).assertError(Exception::class.java)
}
@Test
fun whenMerge_thenStream() {
val observables = mutableListOf(Observable.just("first", "second"))
val observable = observables.merge()
observables.add(Observable.just("third", "fourth"))
observables.add(Observable.error(Exception("e")))
observables.add(Observable.just("fifth"))
observable.test().assertValues("first", "second", "third", "fourth").assertError(Exception::class.java)
}
@Test
fun whenMergeDelayError_thenStream() {
val observables = mutableListOf<Observable<String>>(Observable.error(Exception("e1")))
val observable = observables.mergeDelayError()
observables.add(Observable.just("1", "2"))
observables.add(Observable.error(Exception("e2")))
observables.add(Observable.just("3"))
observable.test().assertValues("1", "2", "3").assertError(Exception::class.java)
}
@Test
fun whenCast_thenUniformType() {
val observable = Observable.just<Number>(1, 1, 2, 3)
observable.cast<Int>().test().assertValues(1, 1, 2, 3)
}
@Test
fun whenOfType_thenFilter() {
val observable = Observable.just(1, "and", 2, "and")
observable.ofType<Int>().test().assertValues(1, 2)
}
@Test
fun whenFunction_thenCompletable() {
var value = 0
val completable = { value = 3 }.toCompletable()
assertFalse(completable.test().isCancelled)
assertEquals(3, value)
}
@Test
fun whenHelper_thenMoreIdiomaticKotlin() {
val zipWith = Observable.just(1).zipWith(Observable.just(2)) { a, b -> a + b }
zipWith.subscribeBy(onNext = { println(it) })
val zip = Observables.zip(Observable.just(1), Observable.just(2)) { a, b -> a + b }
zip.subscribeBy(onNext = { println(it) })
val zipOrig = Observable.zip(Observable.just(1), Observable.just(2), BiFunction<Int, Int, Int> { a, b -> a + b })
zipOrig.subscribeBy(onNext = { println(it) })
}
}

View File

@ -1,4 +1,4 @@
package com.baeldung.jpadefaultvalues.application;
package com.baeldung.jpa.defaultvalues;
import javax.persistence.Column;
import javax.persistence.Entity;
@ -9,7 +9,6 @@ import javax.persistence.Id;
public class User {
@Id
@GeneratedValue
private Long id;
@Column(columnDefinition = "varchar(255) default 'John Snow'")

View File

@ -0,0 +1,36 @@
package com.baeldung.jpa.defaultvalues;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class UserRepository {
private EntityManagerFactory emf = null;
public UserRepository() {
emf = Persistence.createEntityManagerFactory("entity-default-values");
}
public User find(Long id) {
EntityManager entityManager = emf.createEntityManager();
User user = entityManager.find(User.class, id);
entityManager.close();
return user;
}
public void save(User user, Long id) {
user.setId(id);
EntityManager entityManager = emf.createEntityManager();
entityManager.getTransaction().begin();
entityManager.persist(user);
entityManager.getTransaction().commit();
entityManager.close();
}
public void clean() {
emf.close();
}
}

View File

@ -130,4 +130,20 @@
</properties>
</persistence-unit>
<persistence-unit name="entity-default-values">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.baeldung.jpa.defaultvalues.User</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test" />
<property name="javax.persistence.jdbc.user" value="sa" />
<property name="javax.persistence.jdbc.password" value="" />
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="show_sql" value="true" />
<property name="hibernate.temp.use_jdbc_metadata_defaults" value="false" />
</properties>
</persistence-unit>
</persistence>

View File

@ -1,31 +1,31 @@
package com.baeldung.jpadefaultvalues.application;
package com.baeldung.jpa.defaultvalues;
import com.baeldung.jpadefaultvalues.application.User;
import com.baeldung.jpadefaultvalues.application.UserRepository;
import com.baeldung.jpa.defaultvalues.User;
import com.baeldung.jpa.defaultvalues.UserRepository;
import org.junit.Test;
import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.beans.factory.annotation.Autowired;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import static org.junit.Assert.*;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserDefaultValuesUnitTest {
@Autowired
private UserRepository userRepository;
private static UserRepository userRepository = null;
@BeforeClass
public static void once() {
userRepository = new UserRepository();
}
@Test
@Ignore // SQL default values are also defined
public void saveUser_shouldSaveWithDefaultFieldValues() {
User user = new User();
user = userRepository.save(user);
userRepository.save(user, 1L);
user = userRepository.find(1L);
assertEquals(user.getName(), "John Snow");
assertEquals(25, (int) user.getAge());
assertFalse(user.getLocked());
@ -36,8 +36,9 @@ public class UserDefaultValuesUnitTest {
public void saveUser_shouldSaveWithNullName() {
User user = new User();
user.setName(null);
user = userRepository.save(user);
userRepository.save(user, 2L);
user = userRepository.find(2L);
assertNull(user.getName());
assertEquals(25, (int) user.getAge());
assertFalse(user.getLocked());
@ -46,11 +47,17 @@ public class UserDefaultValuesUnitTest {
@Test
public void saveUser_shouldSaveWithDefaultSqlValues() {
User user = new User();
user = userRepository.save(user);
userRepository.save(user, 3L);
user = userRepository.find(3L);
assertEquals(user.getName(), "John Snow");
assertEquals(25, (int) user.getAge());
assertFalse(user.getLocked());
}
@AfterClass
public static void destroy() {
userRepository.clean();
}
}

View File

@ -1,14 +0,0 @@
package com.baeldung.jpadefaultvalues.application;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class Application {
private static ApplicationContext applicationContext;
public static void main(String[] args) {
applicationContext = SpringApplication.run(Application.class, args);
}
}

View File

@ -1,8 +0,0 @@
package com.baeldung.jpadefaultvalues.application;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

View File

@ -0,0 +1,70 @@
package com.baeldung.derivedquery.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.time.ZonedDateTime;
@Table(name = "users")
@Entity
public class User {
@Id
@GeneratedValue
private Integer id;
private String name;
private Integer age;
private ZonedDateTime birthDate;
private Boolean active;
public User() {
}
public User(String name, Integer age, ZonedDateTime birthDate, Boolean active) {
this.name = name;
this.age = age;
this.birthDate = birthDate;
this.active = active;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public ZonedDateTime getBirthDate() {
return birthDate;
}
public void setBirthDate(ZonedDateTime birthDate) {
this.birthDate = birthDate;
}
public Boolean getActive() {
return active;
}
public void setActive(Boolean active) {
this.active = active;
}
}

View File

@ -0,0 +1,60 @@
package com.baeldung.derivedquery.repository;
import com.baeldung.derivedquery.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.List;
public interface UserRepository extends JpaRepository<User, Integer> {
List<User> findByName(String name);
List<User> findByNameIs(String name);
List<User> findByNameEquals(String name);
List<User> findByNameIsNull();
List<User> findByNameNot(String name);
List<User> findByNameIsNot(String name);
List<User> findByNameStartingWith(String name);
List<User> findByNameEndingWith(String name);
List<User> findByNameContaining(String name);
List<User> findByNameLike(String name);
List<User> findByAgeLessThan(Integer age);
List<User> findByAgeLessThanEqual(Integer age);
List<User> findByAgeGreaterThan(Integer age);
List<User> findByAgeGreaterThanEqual(Integer age);
List<User> findByAgeBetween(Integer startAge, Integer endAge);
List<User> findByBirthDateAfter(ZonedDateTime birthDate);
List<User> findByBirthDateBefore(ZonedDateTime birthDate);
List<User> findByActiveTrue();
List<User> findByActiveFalse();
List<User> findByAgeIn(Collection<Integer> ages);
List<User> findByNameOrBirthDate(String name, ZonedDateTime birthDate);
List<User> findByNameOrBirthDateAndActive(String name, ZonedDateTime birthDate, Boolean active);
List<User> findByNameOrderByName(String name);
List<User> findByNameOrderByNameDesc(String name);
}

View File

@ -0,0 +1,172 @@
package com.baeldung.derivedquery.repository;
import com.baeldung.Application;
import com.baeldung.derivedquery.entity.User;
import com.baeldung.derivedquery.repository.UserRepository;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.Assert.assertEquals;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class UserRepositoryTest {
private static final String USER_NAME_ADAM = "Adam";
private static final String USER_NAME_EVE = "Eve";
private static final ZonedDateTime BIRTHDATE = ZonedDateTime.now();
@Autowired
private UserRepository userRepository;
@Before
public void setUp() {
User user1 = new User(USER_NAME_ADAM, 25, BIRTHDATE, true);
User user2 = new User(USER_NAME_ADAM, 20, BIRTHDATE, false);
User user3 = new User(USER_NAME_EVE, 20, BIRTHDATE, true);
User user4 = new User(null, 30, BIRTHDATE, false);
userRepository.saveAll(Arrays.asList(user1, user2, user3, user4));
}
@After
public void tearDown() {
userRepository.deleteAll();
}
@Test
public void whenFindByName_thenReturnsCorrectResult() {
assertEquals(2, userRepository.findByName(USER_NAME_ADAM).size());
}
@Test
public void whenFindByNameIsNull_thenReturnsCorrectResult() {
assertEquals(1, userRepository.findByNameIsNull().size());
}
@Test
public void whenFindByNameNot_thenReturnsCorrectResult() {
assertEquals(USER_NAME_EVE, userRepository.findByNameNot(USER_NAME_ADAM).get(0).getName());
}
@Test
public void whenFindByNameStartingWith_thenReturnsCorrectResult() {
assertEquals(2, userRepository.findByNameStartingWith("A").size());
}
@Test
public void whenFindByNameEndingWith_thenReturnsCorrectResult() {
assertEquals(1, userRepository.findByNameEndingWith("e").size());
}
@Test
public void whenByNameContaining_thenReturnsCorrectResult() {
assertEquals(1, userRepository.findByNameContaining("v").size());
}
@Test
public void whenByNameLike_thenReturnsCorrectResult() {
assertEquals(2, userRepository.findByNameEndingWith("%d%m").size());
}
@Test
public void whenByAgeLessThan_thenReturnsCorrectResult() {
assertEquals(2, userRepository.findByAgeLessThan(25).size());
}
@Test
public void whenByAgeLessThanEqual_thenReturnsCorrectResult() {
assertEquals(3, userRepository.findByAgeLessThanEqual(25).size());
}
@Test
public void whenByAgeGreaterThan_thenReturnsCorrectResult() {
assertEquals(1, userRepository.findByAgeGreaterThan(25).size());
}
@Test
public void whenByAgeGreaterThanEqual_thenReturnsCorrectResult() {
assertEquals(2, userRepository.findByAgeGreaterThanEqual(25).size());
}
@Test
public void whenByAgeBetween_thenReturnsCorrectResult() {
assertEquals(4, userRepository.findByAgeBetween(20, 30).size());
}
@Test
public void whenByBirthDateAfter_thenReturnsCorrectResult() {
final ZonedDateTime yesterday = BIRTHDATE.minusDays(1);
assertEquals(4, userRepository.findByBirthDateAfter(yesterday).size());
}
@Test
public void whenByBirthDateBefore_thenReturnsCorrectResult() {
final ZonedDateTime yesterday = BIRTHDATE.minusDays(1);
assertEquals(0, userRepository.findByBirthDateBefore(yesterday).size());
}
@Test
public void whenByActiveTrue_thenReturnsCorrectResult() {
assertEquals(2, userRepository.findByActiveTrue().size());
}
@Test
public void whenByActiveFalse_thenReturnsCorrectResult() {
assertEquals(2, userRepository.findByActiveFalse().size());
}
@Test
public void whenByAgeIn_thenReturnsCorrectResult() {
final List<Integer> ages = Arrays.asList(20, 25);
assertEquals(3, userRepository.findByAgeIn(ages).size());
}
@Test
public void whenByNameOrBirthDate() {
assertEquals(4, userRepository.findByNameOrBirthDate(USER_NAME_ADAM, BIRTHDATE).size());
}
@Test
public void whenByNameOrBirthDateAndActive() {
assertEquals(3, userRepository.findByNameOrBirthDateAndActive(USER_NAME_ADAM, BIRTHDATE, false).size());
}
@Test
public void whenByNameOrderByName() {
assertEquals(2, userRepository.findByNameOrderByName(USER_NAME_ADAM).size());
}
}

View File

@ -608,6 +608,7 @@
<module>spring-5-reactive-security</module>
<module>spring-5-security</module>
<module>spring-5-security-oauth</module>
<module>spring-5-security-cognito</module>
<module>spring-activiti</module>
<module>spring-akka</module>
@ -819,6 +820,7 @@
<module>spring-5-reactive-security</module>
<module>spring-5-security</module>
<module>spring-5-security-oauth</module>
<module>spring-5-security-cognito</module>
<module>spring-activiti</module>
<module>spring-akka</module>
<module>spring-all</module>
@ -1271,7 +1273,7 @@
<module>spring-5-reactive-security</module>
<module>spring-5-security</module>
<module>spring-5-security-oauth</module>
<module>spring-5-security-cognito</module>
<module>spring-activiti</module>
<module>spring-akka</module>
<module>spring-all</module>

View File

@ -10,6 +10,7 @@
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<dependencies>

View File

@ -10,6 +10,7 @@
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<dependencies>

View File

@ -10,6 +10,7 @@
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<dependencies>

View File

@ -17,6 +17,7 @@
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
@ -53,6 +54,11 @@
<artifactId>hibernate-jpamodelgen</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,3 @@
## Relevant articles:
- [Authenticating with Amazon Cognito Using Spring Security](https://www.baeldung.com/spring-security-oauth-cognito)

View File

@ -0,0 +1,74 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung</groupId>
<artifactId>spring-5-security-cognito</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-5-security-cognito</name>
<packaging>jar</packaging>
<description>spring 5 security oauth cognito sample project</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-boot-2</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<!-- oauth2 -->
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>${oauth-auto.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<spring-boot.version>2.1.0.RELEASE</spring-boot.version>
<oauth-auto.version>2.1.0.RELEASE</oauth-auto.version>
<start-class>com.baeldung.cognito.SpringCognitoApplication</start-class>
</properties>
</project>

View File

@ -6,7 +6,7 @@ import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@PropertySource("cognito/application_cognito.yml")
@PropertySource("cognito/application-cognito.yml")
public class CognitoWebConfiguration implements WebMvcConfigurer {
@Override

View File

@ -5,7 +5,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;
@SpringBootApplication
@PropertySource("cognito/application_cognito.yml")
@PropertySource("cognito/application-cognito.yml")
public class SpringCognitoApplication {
public static void main(String[] args) {

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -16,6 +16,20 @@
<relativePath>../parent-boot-2</relativePath>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<!-- <version>2.0.4.RELEASE</version> --><!-- works -->
<version>2.1.3.RELEASE</version> <!-- Works with workaround applied -->
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -3,6 +3,12 @@ package org.baeldung.spring.amqp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.web.filter.reactive.HiddenHttpMethodFilter;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
@SpringBootApplication
@EnableConfigurationProperties(DestinationsConfig.class)
@ -12,4 +18,19 @@ public class SpringWebfluxAmqpApplication {
SpringApplication.run(SpringWebfluxAmqpApplication.class, args);
}
/**
* This is a workaround for https://github.com/spring-projects/spring-framework/issues/21094
* @return
*/
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new HiddenHttpMethodFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return chain.filter(exchange);
}
};
}
}

View File

@ -1,6 +1,6 @@
spring:
rabbitmq:
host: localhost
host: 192.168.99.100
port: 5672
username: guest
password: guest