fix conflicts
This commit is contained in:
+2
-1
@@ -76,4 +76,5 @@ persistence-modules/hibernate5/transaction.log
|
||||
apache-avro/src/main/java/com/baeldung/avro/model/
|
||||
jta/transaction-logs/
|
||||
software-security/sql-injection-samples/derby.log
|
||||
spring-soap/src/main/java/com/baeldung/springsoap/gen/
|
||||
spring-soap/src/main/java/com/baeldung/springsoap/gen/
|
||||
/report-*.json
|
||||
@@ -60,7 +60,6 @@
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<junit.version>4.10</junit.version>
|
||||
<meecrowave-junit.version>1.2.0</meecrowave-junit.version>
|
||||
<okhttp.version>3.10.0</okhttp.version>
|
||||
<meecrowave-jpa.version>1.2.1</meecrowave-jpa.version>
|
||||
|
||||
@@ -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|
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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/
|
||||
@@ -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>
|
||||
+298
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+14
@@ -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);
|
||||
}
|
||||
}
|
||||
+36
@@ -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;
|
||||
|
||||
|
||||
}
|
||||
+38
@@ -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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
server:
|
||||
port: 8180
|
||||
|
||||
spring:
|
||||
jersey:
|
||||
application-path: /odata
|
||||
|
||||
jpa:
|
||||
show-sql: true
|
||||
open-in-view: false
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
@@ -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;
|
||||
+16
@@ -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() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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/
|
||||
@@ -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>
|
||||
+20
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.baeldung.examples.olingo4;
|
||||
|
||||
import org.apache.olingo.server.api.OData;
|
||||
|
||||
public interface ODataFactory {
|
||||
|
||||
public OData newInstance();
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package org.baeldung.examples.olingo4;
|
||||
|
||||
import org.apache.olingo.server.api.ODataHttpHandler;
|
||||
|
||||
public interface ODataHttpHandlerFactory {
|
||||
|
||||
ODataHttpHandler newInstance();
|
||||
}
|
||||
+42
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+35
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
+13
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -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;
|
||||
|
||||
|
||||
}
|
||||
+38
@@ -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;
|
||||
|
||||
}
|
||||
+46
@@ -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())));
|
||||
|
||||
}
|
||||
+269
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+161
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+93
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+304
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user