Merge remote-tracking branch 'eugenp/master'

This commit is contained in:
DOHA 2019-05-14 14:52:45 +02:00
commit 8754806e7e
355 changed files with 8270 additions and 639 deletions

View File

@ -15,3 +15,5 @@
- [Calculate Percentage in Java](https://www.baeldung.com/java-calculate-percentage)
- [Converting Between Byte Arrays and Hexadecimal Strings in Java](https://www.baeldung.com/java-byte-arrays-hex-strings)
- [Convert Latitude and Longitude to a 2D Point in Java](https://www.baeldung.com/java-convert-latitude-longitude)
- [Reversing a Binary Tree in Java](https://www.baeldung.com/java-reversing-a-binary-tree)
- [Find If Two Numbers Are Relatively Prime in Java](https://www.baeldung.com/java-two-relatively-prime-numbers)

View File

@ -4,4 +4,3 @@
- [Implementing Simple State Machines with Java Enums](https://www.baeldung.com/java-enum-simple-state-machine)
- [Converting Between Roman and Arabic Numerals in Java](http://www.baeldung.com/java-convert-roman-arabic)
- [Practical Java Examples of the Big O Notation](http://www.baeldung.com/java-algorithm-complexity)
- [An Introduction to the Theory of Big-O Notation](http://www.baeldung.com/big-o-notation)

View File

@ -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>

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|

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

@ -1,4 +1,4 @@
package com.baeldung.jsonexception;
package org.baeldung.examples.olingo2;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -7,10 +7,10 @@ import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringContextIntegrationTest {
public class Olingo2SampleApplicationTests {
@Test
public void contextLoads() {
}
@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

@ -1,13 +1,13 @@
package com.baeldung.jsonexception;
package org.baeldung.examples.olingo4;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class JsonErrorApplication {
public class Olingo4SampleApplication {
public static void main(String[] args) {
SpringApplication.run(JsonErrorApplication.class, 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

@ -59,7 +59,6 @@
</build>
<properties>
<jstl.version>1.2</jstl.version>
<org.apache.httpcomponents.version>4.5.2</org.apache.httpcomponents.version>
<velocity-version>1.7</velocity-version>
<velocity-tools-version>2.0</velocity-tools-version>

View File

@ -27,7 +27,7 @@
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>${hamcrest-core.version}</version>
<version>${org.hamcrest.version}</version>
<scope>test</scope>
</dependency>
<dependency>
@ -64,7 +64,6 @@
<cdi-api.version>2.0.SP1</cdi-api.version>
<weld-se-core.version>3.0.5.Final</weld-se-core.version>
<aspectjweaver.version>1.9.2</aspectjweaver.version>
<hamcrest-core.version>1.3</hamcrest-core.version>
<assertj-core.version>3.10.0</assertj-core.version>
<spring.version>5.1.2.RELEASE</spring.version>
</properties>

View File

@ -34,8 +34,5 @@
</plugin>
</plugins>
</build>
<properties>
<java.version>1.8</java.version>
</properties>
</project>

View File

@ -35,8 +35,4 @@
</plugins>
</build>
<properties>
<java.version>1.8</java.version>
</properties>
</project>

View File

@ -3,5 +3,5 @@
## Relevant articles:
- [String Matching in Groovy](http://www.baeldung.com/)
- [Groovy def Keyword]
- [Groovy def Keyword](https://www.baeldung.com/groovy-def-keyword)
- [Pattern Matching in Strings in Groovy](https://www.baeldung.com/groovy-pattern-matching)

View File

@ -0,0 +1,5 @@
Dear <% out << (user) %>,
Please read the requested article below.
<% out << (articleText) %>
From,
<% out << (signature) %>

View File

@ -0,0 +1,3 @@
Dear $user,
Thanks for subscribing our services.
${signature}

View File

@ -0,0 +1,96 @@
package com.baeldung.templateengine
import groovy.text.SimpleTemplateEngine
import groovy.text.StreamingTemplateEngine
import groovy.text.GStringTemplateEngine
import groovy.text.XmlTemplateEngine
import groovy.text.XmlTemplateEngine
import groovy.text.markup.MarkupTemplateEngine
import groovy.text.markup.TemplateConfiguration
class TemplateEnginesUnitTest extends GroovyTestCase {
def bindMap = [user: "Norman", signature: "Baeldung"]
void testSimpleTemplateEngine() {
def smsTemplate = 'Dear <% print user %>, Thanks for reading our Article. ${signature}'
def smsText = new SimpleTemplateEngine().createTemplate(smsTemplate).make(bindMap)
assert smsText.toString() == "Dear Norman, Thanks for reading our Article. Baeldung"
}
void testStreamingTemplateEngine() {
def articleEmailTemplate = new File('src/main/resources/articleEmail.template')
bindMap.articleText = """1. Overview
This is a tutorial article on Template Engines""" //can be a string larger than 64k
def articleEmailText = new StreamingTemplateEngine().createTemplate(articleEmailTemplate).make(bindMap)
assert articleEmailText.toString() == """Dear Norman,
Please read the requested article below.
1. Overview
This is a tutorial article on Template Engines
From,
Baeldung"""
}
void testGStringTemplateEngine() {
def emailTemplate = new File('src/main/resources/email.template')
def emailText = new GStringTemplateEngine().createTemplate(emailTemplate).make(bindMap)
assert emailText.toString() == "Dear Norman,\nThanks for subscribing our services.\nBaeldung"
}
void testXmlTemplateEngine() {
def emailXmlTemplate = '''<xs xmlns:gsp='groovy-server-pages'>
<gsp:scriptlet>def emailContent = "Thanks for subscribing our services."</gsp:scriptlet>
<email>
<greet>Dear ${user}</greet>
<content><gsp:expression>emailContent</gsp:expression></content>
<signature>${signature}</signature>
</email>
</xs>'''
def emailXml = new XmlTemplateEngine().createTemplate(emailXmlTemplate).make(bindMap)
println emailXml.toString()
}
void testMarkupTemplateEngineHtml() {
def emailHtmlTemplate = """html {
head {
title('Service Subscription Email')
}
body {
p('Dear Norman')
p('Thanks for subscribing our services.')
p('Baeldung')
}
}"""
def emailHtml = new MarkupTemplateEngine().createTemplate(emailHtmlTemplate).make()
println emailHtml.toString()
}
void testMarkupTemplateEngineXml() {
def emailXmlTemplate = """xmlDeclaration()
xs{
email {
greet('Dear Norman')
content('Thanks for subscribing our services.')
signature('Baeldung')
}
}
"""
TemplateConfiguration config = new TemplateConfiguration()
config.autoIndent = true
config.autoEscape = true
config.autoNewLine = true
def emailXml = new MarkupTemplateEngine(config).createTemplate(emailXmlTemplate).make()
println emailXml.toString()
}
}

View File

@ -2,5 +2,5 @@
## Relevant articles:
- [Maps in Groovy](http://www.baeldung.com/)
- [Maps in Groovy](https://www.baeldung.com/groovy-maps)

View File

@ -0,0 +1,3 @@
## Relevant Articles
- [Extending an Arrays Length](https://www.baeldung.com/java-array-add-element-at-the-end)

View File

@ -0,0 +1,52 @@
package com.baeldung.array.conversions;
import java.util.Arrays;
import java.util.function.IntFunction;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class StreamArrayConversion {
public static String[] stringStreamToStringArrayUsingFunctionalInterface(Stream<String> stringStream) {
IntFunction<String[]> intFunction = new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
return new String[value];
}
};
return stringStream.toArray(intFunction);
}
public static String[] stringStreamToStringArrayUsingMethodReference(Stream<String> stringStream) {
return stringStream.toArray(String[]::new);
}
public static String[] stringStreamToStringArrayUsingLambda(Stream<String> stringStream) {
return stringStream.toArray(value -> new String[value]);
}
public static Integer[] integerStreamToIntegerArray(Stream<Integer> integerStream) {
return integerStream.toArray(Integer[]::new);
}
public static int[] intStreamToPrimitiveIntArray(Stream<Integer> integerStream) {
return integerStream.mapToInt(i -> i).toArray();
}
public static Stream<String> stringArrayToStreamUsingArraysStream(String[] stringArray) {
return Arrays.stream(stringArray);
}
public static Stream<String> stringArrayToStreamUsingStreamOf(String[] stringArray) {
return Stream.of(stringArray);
}
public static IntStream primitiveIntArrayToStreamUsingArraysStream(int[] intArray) {
return Arrays.stream(intArray);
}
public static Stream<int[]> primitiveIntArrayToStreamUsingStreamOf(int[] intArray) {
return Stream.of(intArray);
}
}

View File

@ -0,0 +1,70 @@
package com.baeldung.array.conversions;
import static com.baeldung.array.conversions.StreamArrayConversion.intStreamToPrimitiveIntArray;
import static com.baeldung.array.conversions.StreamArrayConversion.integerStreamToIntegerArray;
import static com.baeldung.array.conversions.StreamArrayConversion.stringStreamToStringArrayUsingFunctionalInterface;
import static com.baeldung.array.conversions.StreamArrayConversion.stringStreamToStringArrayUsingLambda;
import static com.baeldung.array.conversions.StreamArrayConversion.stringStreamToStringArrayUsingMethodReference;
import static com.baeldung.array.conversions.StreamArrayConversion.stringArrayToStreamUsingArraysStream;
import static com.baeldung.array.conversions.StreamArrayConversion.stringArrayToStreamUsingStreamOf;
import static com.baeldung.array.conversions.StreamArrayConversion.primitiveIntArrayToStreamUsingArraysStream;
import static com.baeldung.array.conversions.StreamArrayConversion.primitiveIntArrayToStreamUsingStreamOf;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import com.google.common.collect.Iterators;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.Test;
public class StreamArrayConversionUnitTest {
private String[] stringArray = new String[]{"baeldung", "convert", "to", "string", "array"};
private Integer[] integerArray = new Integer[]{1, 2, 3, 4, 5, 6, 7};
private int[] intPrimitiveArray = new int[]{1, 2, 3, 4, 5, 6, 7};
@Test
public void givenStringStream_thenConvertToStringArrayUsingFunctionalInterface() {
Stream<String> stringStream = Stream.of("baeldung", "convert", "to", "string", "array");
assertArrayEquals(stringArray, stringStreamToStringArrayUsingFunctionalInterface(stringStream));
}
@Test
public void givenStringStream_thenConvertToStringArrayUsingMethodReference() {
Stream<String> stringStream = Stream.of("baeldung", "convert", "to", "string", "array");
assertArrayEquals(stringArray, stringStreamToStringArrayUsingMethodReference(stringStream));
}
@Test
public void givenStringStream_thenConvertToStringArrayUsingLambda() {
Stream<String> stringStream = Stream.of("baeldung", "convert", "to", "string", "array");
assertArrayEquals(stringArray, stringStreamToStringArrayUsingLambda(stringStream));
}
@Test
public void givenIntegerStream_thenConvertToIntegerArray() {
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6, 7);
assertArrayEquals(integerArray, integerStreamToIntegerArray(integerStream));
}
@Test
public void givenIntStream_thenConvertToIntegerArray() {
Stream<Integer> integerStream = IntStream.rangeClosed(1, 7).boxed();
assertArrayEquals(intPrimitiveArray, intStreamToPrimitiveIntArray(integerStream));
}
@Test
public void givenStringArray_whenConvertedTwoWays_thenConvertedStreamsAreEqual() {
assertTrue(Iterators
.elementsEqual(stringArrayToStreamUsingArraysStream(stringArray).iterator(),
stringArrayToStreamUsingStreamOf(stringArray).iterator()));
}
@Test
public void givenPrimitiveArray_whenConvertedTwoWays_thenConvertedStreamsAreNotEqual() {
assertFalse(Iterators.elementsEqual(
primitiveIntArrayToStreamUsingArraysStream(intPrimitiveArray).iterator(),
primitiveIntArrayToStreamUsingStreamOf(intPrimitiveArray).iterator()));
}
}

View File

@ -0,0 +1,2 @@
### Relevant Articles:
- [Java 9 java.lang.Module API](https://www.baeldung.com/java-lambda-effectively-final-local-variables)

View File

@ -7,3 +7,4 @@
- [Exploring the New HTTP Client in Java 9 and 11](https://www.baeldung.com/java-9-http-client)
- [An Introduction to Epsilon GC: A No-Op Experimental Garbage Collector](https://www.baeldung.com/jvm-epsilon-gc-garbage-collector)
- [Guide to jlink](https://www.baeldung.com/jlink)
- [Transforming an Empty String into an Empty Optional](https://www.baeldung.com/java-empty-string-to-empty-optional)

View File

@ -3,4 +3,5 @@
## Core Java 8 Cookbooks and Examples (part 2)
### Relevant Articles:
- [Anonymous Classes in Java](http://www.baeldung.com/)
- [Anonymous Classes in Java](https://www.baeldung.com/java-anonymous-classes)
- [Run JAR Application With Command Line Arguments](https://www.baeldung.com/java-run-jar-with-arguments)

View File

@ -101,7 +101,7 @@ public class OptionalChainingUnitTest {
}
private Optional<String> createOptional(String input) {
if (input == null || input == "" || input == "empty") {
if (input == null || "".equals(input) || "empty".equals(input)) {
return Optional.empty();
}

View File

@ -20,6 +20,14 @@
- [Multi-Release Jar Files](https://www.baeldung.com/java-multi-release-jar)
- [Ahead of Time Compilation (AoT)](https://www.baeldung.com/ahead-of-time-compilation)
- [Java 9 Process API Improvements](https://www.baeldung.com/java-9-process-api)
- [Guide to java.lang.Process API](https://www.baeldung.com/java-process-api)
- [Java 9 java.util.Objects Additions](https://www.baeldung.com/java-9-objects-new)
- [Java 9 Reactive Streams](https://www.baeldung.com/java-9-reactive-streams)
- [Java 9 Optional API Additions](https://www.baeldung.com/java-9-optional)
- [Java 9 CompletableFuture API Improvements](https://www.baeldung.com/java-9-completablefuture)
- [Introduction to Java 9 StackWalking API](https://www.baeldung.com/java-9-stackwalking-api)
- [Java 9 Convenience Factory Methods for Collections](https://www.baeldung.com/java-9-collections-factory-methods)
- [Java 9 Stream API Improvements](https://www.baeldung.com/java-9-stream-api)
- [A Guide to Java 9 Modularity](https://www.baeldung.com/java-9-modularity)
- [Java 9 Platform Module API](https://www.baeldung.com/java-9-module-api)
- [Java 9 Platform Logging API](https://www.baeldung.com/java-9-logging-api)
- [Filtering a Stream of Optionals in Java](https://www.baeldung.com/java-filter-stream-of-optional)

View File

@ -8,4 +8,5 @@
- [A Guide to HashSet in Java](http://www.baeldung.com/java-hashset)
- [A Guide to TreeSet in Java](http://www.baeldung.com/java-tree-set)
- [Initializing HashSet at the Time of Construction](http://www.baeldung.com/java-initialize-hashset)
- [Guide to EnumSet](https://www.baeldung.com/java-enumset)
- [Guide to EnumSet](https://www.baeldung.com/java-enumset)
- [Set Operations in Java](https://www.baeldung.com/java-set-operations)

View File

@ -0,0 +1,26 @@
<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.exception.numberformat</groupId>
<artifactId>core-java-exceptions</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>core-java-exceptions</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-java</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-java</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,154 @@
package com.baeldung.exception.numberformat;
import static org.junit.Assert.assertEquals;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
import java.util.logging.Logger;
import org.junit.Test;
/**
* A set of examples tested to show cases where NumberFormatException is thrown and not thrown.
*/
public class NumberFormatExceptionUnitTest {
Logger LOG = Logger.getLogger(NumberFormatExceptionUnitTest.class.getName());
/* ---INTEGER FAIL CASES--- */
@Test(expected = NumberFormatException.class)
public void givenByteConstructor_whenAlphabetAsInput_thenFail() {
Byte byteInt = new Byte("one");
}
@Test(expected = NumberFormatException.class)
public void givenShortConstructor_whenSpaceInInput_thenFail() {
Short shortInt = new Short("2 ");
}
@Test(expected = NumberFormatException.class)
public void givenParseIntMethod_whenSpaceInInput_thenFail() {
Integer aIntPrim = Integer.parseInt("6000 ");
}
@Test(expected = NumberFormatException.class)
public void givenParseIntMethod_whenUnderscoreInInput_thenFail() {
int bIntPrim = Integer.parseInt("6_000");
}
@Test(expected = NumberFormatException.class)
public void givenIntegerValueOfMethod_whenCommaInInput_thenFail() {
Integer cIntPrim = Integer.valueOf("6,000");
}
@Test(expected = NumberFormatException.class)
public void givenBigIntegerConstructor_whenDecimalInInput_thenFail() {
BigInteger bigInteger = new BigInteger("4.0");
}
@Test(expected = NumberFormatException.class)
public void givenDecodeMethod_whenAlphabetInInput_thenFail() {
Long decodeInteger = Long.decode("64403L");
}
/* ---INTEGER PASS CASES--- */
@Test
public void givenInvalidNumberInputs_whenOptimized_thenPass() {
Byte byteInt = new Byte("1");
assertEquals(1, byteInt.intValue());
Short shortInt = new Short("2 ".trim());
assertEquals(2, shortInt.intValue());
Integer aIntObj = Integer.valueOf("6");
assertEquals(6, aIntObj.intValue());
BigInteger bigInteger = new BigInteger("4");
assertEquals(4, bigInteger.intValue());
int aIntPrim = Integer.parseInt("6000 ".trim());
assertEquals(6000, aIntPrim);
int bIntPrim = Integer.parseInt("6_000".replaceAll("_", ""));
assertEquals(6000, bIntPrim);
int cIntPrim = Integer.parseInt("-6000");
assertEquals(-6000, cIntPrim);
Long decodeInteger = Long.decode("644032334");
assertEquals(644032334L, decodeInteger.longValue());
}
/* ---DOUBLE FAIL CASES--- */
@Test(expected = NumberFormatException.class)
public void givenFloatConstructor_whenAlphabetInInput_thenFail() {
Float floatDecimalObj = new Float("one.1");
}
@Test(expected = NumberFormatException.class)
public void givenDoubleConstructor_whenAlphabetInInput_thenFail() {
Double doubleDecimalObj = new Double("two.2");
}
@Test(expected = NumberFormatException.class)
public void givenBigDecimalConstructor_whenSpecialCharsInInput_thenFail() {
BigDecimal bigDecimalObj = new BigDecimal("3_0.3");
}
@Test(expected = NumberFormatException.class)
public void givenParseDoubleMethod_whenCommaInInput_thenFail() {
double aDoublePrim = Double.parseDouble("4000,1");
}
/* ---DOUBLE PASS CASES--- */
@Test
public void givenDoubleConstructor_whenDecimalInInput_thenPass() {
Double doubleDecimalObj = new Double("2.2");
assertEquals(2.2, doubleDecimalObj.doubleValue(), 0);
}
@Test
public void givenDoubleValueOfMethod_whenMinusInInput_thenPass() {
Double aDoubleObj = Double.valueOf("-6000");
assertEquals(-6000, aDoubleObj.doubleValue(), 0);
}
@Test
public void givenUsDecimalNumber_whenParsedWithNumberFormat_thenPass() throws ParseException {
Number parsedNumber = parseNumberWithLocale("4000.1", Locale.US);
assertEquals(4000.1, parsedNumber);
assertEquals(4000.1, parsedNumber.doubleValue(), 0);
assertEquals(4000, parsedNumber.intValue());
}
/**
* In most European countries (for example, France), comma is used as decimal in place of period.
* @throws ParseException if the input string contains special characters other than comma or decimal.
* In this test case, anything after decimal (period) is dropped when a European locale is set.
*/
@Test
public void givenEuDecimalNumberHasComma_whenParsedWithNumberFormat_thenPass() throws ParseException {
Number parsedNumber = parseNumberWithLocale("4000,1", Locale.FRANCE);
LOG.info("Number parsed is: " + parsedNumber);
assertEquals(4000.1, parsedNumber);
assertEquals(4000.1, parsedNumber.doubleValue(), 0);
assertEquals(4000, parsedNumber.intValue());
}
/**
* Converts a string into a number retaining all decimals, and symbols valid in a locale.
* @param number the input string for a number.
* @param locale the locale to consider while parsing a number.
* @return the generic number object which can represent multiple number types.
* @throws ParseException when input contains invalid characters.
*/
private Number parseNumberWithLocale(String number, Locale locale) throws ParseException {
locale = locale == null ? Locale.getDefault() : locale;
NumberFormat numberFormat = NumberFormat.getInstance(locale);
return numberFormat.parse(number);
}
}

View File

@ -40,3 +40,4 @@
- [How to Write to a CSV File in Java](https://www.baeldung.com/java-csv)
- [List Files in a Directory in Java](https://www.baeldung.com/java-list-directory-files)
- [Java InputStream to Byte Array and ByteBuffer](https://www.baeldung.com/convert-input-stream-to-array-of-bytes)
- [Introduction to the Java NIO Selector](https://www.baeldung.com/java-nio-selector)

View File

@ -4,3 +4,5 @@
### Relevant Articles:
- [Generic Constructors in Java](https://www.baeldung.com/java-generic-constructors)
- [Cannot Reference “X” Before Supertype Constructor Has Been Called](https://www.baeldung.com/java-cannot-reference-x-before-supertype-constructor-error)
- [Anonymous Classes in Java](https://www.baeldung.com/java-anonymous-classes)

View File

@ -0,0 +1,3 @@
## Relevant Articles
- [Void Type in Java](https://www.baeldung.com/java-void-type)

View File

@ -51,3 +51,4 @@
- [Java Bitwise Operators](https://www.baeldung.com/java-bitwise-operators)
- [Guide to Creating and Running a Jar File in Java](https://www.baeldung.com/java-create-jar)
- [Making a JSON POST Request With HttpURLConnection](https://www.baeldung.com/httpurlconnection-post)
- [Convert Hex to ASCII in Java](https://www.baeldung.com/java-convert-hex-to-ascii)

View File

@ -454,7 +454,7 @@
<gson.version>2.8.2</gson.version>
<!-- util -->
<commons-lang3.version>3.5</commons-lang3.version>
<commons-lang3.version>3.9</commons-lang3.version>
<commons-io.version>2.5</commons-io.version>
<commons-math3.version>3.6.1</commons-math3.version>
<decimal4j.version>1.0.3</decimal4j.version>

View File

@ -0,0 +1,98 @@
package com.baeldung.exceptions;
import java.time.LocalDate;
import java.time.Period;
import java.time.format.DateTimeParseException;
import java.util.Objects;
/**
* Utility class to find root cause exceptions.
*/
public class RootCauseFinder {
private RootCauseFinder() {
}
public static Throwable findCauseUsingPlainJava(Throwable throwable) {
Objects.requireNonNull(throwable);
Throwable rootCause = throwable;
while (rootCause.getCause() != null && rootCause.getCause() != rootCause) {
rootCause = rootCause.getCause();
}
return rootCause;
}
/**
* Calculates the age of a person from a given date.
*/
static class AgeCalculator {
private AgeCalculator() {
}
public static int calculateAge(String birthDate) {
if (birthDate == null || birthDate.isEmpty()) {
throw new IllegalArgumentException();
}
try {
return Period
.between(parseDate(birthDate), LocalDate.now())
.getYears();
} catch (DateParseException ex) {
throw new CalculationException(ex);
}
}
private static LocalDate parseDate(String birthDateAsString) {
LocalDate birthDate;
try {
birthDate = LocalDate.parse(birthDateAsString);
} catch (DateTimeParseException ex) {
throw new InvalidFormatException(birthDateAsString, ex);
}
if (birthDate.isAfter(LocalDate.now())) {
throw new DateOutOfRangeException(birthDateAsString);
}
return birthDate;
}
}
static class CalculationException extends RuntimeException {
CalculationException(DateParseException ex) {
super(ex);
}
}
static class DateParseException extends RuntimeException {
DateParseException(String input) {
super(input);
}
DateParseException(String input, Throwable thr) {
super(input, thr);
}
}
static class InvalidFormatException extends DateParseException {
InvalidFormatException(String input, Throwable thr) {
super("Invalid date format: " + input, thr);
}
}
static class DateOutOfRangeException extends DateParseException {
DateOutOfRangeException(String date) {
super("Date out of range: " + date);
}
}
}

View File

@ -0,0 +1,114 @@
package com.baeldung.exceptions;
import com.google.common.base.Throwables;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import static com.baeldung.exceptions.RootCauseFinder.*;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Tests the {@link RootCauseFinder}.
*/
public class RootCauseFinderUnitTest {
@Test
public void givenBirthDate_whenCalculatingAge_thenAgeReturned() {
try {
int age = AgeCalculator.calculateAge("1990-01-01");
Assertions.assertEquals(1990, LocalDate
.now()
.minus(age, ChronoUnit.YEARS)
.getYear());
} catch (CalculationException e) {
Assertions.fail(e.getMessage());
}
}
@Test
public void givenWrongFormatDate_whenFindingRootCauseUsingJava_thenRootCauseFound() {
try {
AgeCalculator.calculateAge("010102");
} catch (CalculationException ex) {
assertTrue(findCauseUsingPlainJava(ex) instanceof DateTimeParseException);
}
}
@Test
public void givenOutOfRangeDate_whenFindingRootCauseUsingJava_thenRootCauseFound() {
try {
AgeCalculator.calculateAge("2020-04-04");
} catch (CalculationException ex) {
assertTrue(findCauseUsingPlainJava(ex) instanceof DateOutOfRangeException);
}
}
@Test
public void givenNullDate_whenFindingRootCauseUsingJava_thenRootCauseFound() {
try {
AgeCalculator.calculateAge(null);
} catch (Exception ex) {
assertTrue(findCauseUsingPlainJava(ex) instanceof IllegalArgumentException);
}
}
@Test
public void givenWrongFormatDate_whenFindingRootCauseUsingApacheCommons_thenRootCauseFound() {
try {
AgeCalculator.calculateAge("010102");
} catch (CalculationException ex) {
assertTrue(ExceptionUtils.getRootCause(ex) instanceof DateTimeParseException);
}
}
@Test
public void givenOutOfRangeDate_whenFindingRootCauseUsingApacheCommons_thenRootCauseFound() {
try {
AgeCalculator.calculateAge("2020-04-04");
} catch (CalculationException ex) {
assertTrue(ExceptionUtils.getRootCause(ex) instanceof DateOutOfRangeException);
}
}
@Test
public void givenNullDate_whenFindingRootCauseUsingApacheCommons_thenRootCauseNotFound() {
try {
AgeCalculator.calculateAge(null);
} catch (Exception ex) {
assertTrue(ExceptionUtils.getRootCause(ex) instanceof IllegalArgumentException);
}
}
@Test
public void givenWrongFormatDate_whenFindingRootCauseUsingGuava_thenRootCauseFound() {
try {
AgeCalculator.calculateAge("010102");
} catch (CalculationException ex) {
assertTrue(Throwables.getRootCause(ex) instanceof DateTimeParseException);
}
}
@Test
public void givenOutOfRangeDate_whenFindingRootCauseUsingGuava_thenRootCauseFound() {
try {
AgeCalculator.calculateAge("2020-04-04");
} catch (CalculationException ex) {
assertTrue(Throwables.getRootCause(ex) instanceof DateOutOfRangeException);
}
}
@Test
public void givenNullDate_whenFindingRootCauseUsingGuava_thenRootCauseFound() {
try {
AgeCalculator.calculateAge(null);
} catch (Exception ex) {
assertTrue(Throwables.getRootCause(ex) instanceof IllegalArgumentException);
}
}
}

View File

@ -15,6 +15,7 @@
<modules>
<module>pre-jpms</module>
<module>core-java-exceptions</module>
</modules>
</project>

View File

@ -0,0 +1,3 @@
## Relevant Articles
- [Java 9 Migration Issues and Resolutions](https://www.baeldung.com/java-9-migration-issue)

View File

@ -6,4 +6,5 @@
- [Kotlin Scope Functions](https://www.baeldung.com/kotlin-scope-functions)
- [Kotlin Annotations](https://www.baeldung.com/kotlin-annotations)
- [Split a List into Parts in Kotlin](https://www.baeldung.com/kotlin-split-list-into-parts)
- [String Comparison in Kotlin](https://www.baeldung.com/kotlin-string-comparison)
- [String Comparison in Kotlin](https://www.baeldung.com/kotlin-string-comparison)
- [Guide to JVM Platform Annotations in Kotlin](https://www.baeldung.com/kotlin-jvm-annotations)

View File

@ -88,7 +88,7 @@
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${javax-servlet.version}</version>
<version>${javax.servlet-api.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
@ -98,7 +98,7 @@
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>${javax-jsp.version}</version>
<version>${javax.servlet.jsp-api.version}</version>
</dependency>
<!-- Logging -->
@ -160,7 +160,7 @@
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>${hamcrest.version}</version>
<version>${org.hamcrest.version}</version>
<scope>test</scope>
</dependency>
<dependency>
@ -213,12 +213,7 @@
<web3j.core.version>3.3.1</web3j.core.version>
<spring.boot.version>1.5.6.RELEASE</spring.boot.version>
<mockito.version>2.21.0</mockito.version>
<hamcrest.version>1.3</hamcrest.version>
<javax-jsp.version>2.3.1</javax-jsp.version>
<javax-servlet.version>3.1.0</javax-servlet.version>
<jsonpath.version>2.4.0</jsonpath.version>
<jstl.version>1.2</jstl.version>
<junit.version>4.12</junit.version>
<logback.version>1.2.3</logback.version>
<slf4j.version>1.7.25</slf4j.version>
<spring-boot-maven-plugin.version>2.0.4.RELEASE</spring-boot-maven-plugin.version>

View File

@ -30,7 +30,6 @@
</dependencies>
<properties>
<lombok.version>1.16.18</lombok.version>
<google-cloud-storage.version>1.16.0</google-cloud-storage.version>
</properties>

View File

@ -120,7 +120,6 @@
<!-- Don't let your Mac use a crazy non-standard encoding -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<junit.version>4.11</junit.version>
<gwt.version>2.8.2</gwt.version>
</properties>

View File

@ -67,7 +67,6 @@
<commons-lang3.version>3.5</commons-lang3.version>
<commons-collections4.version>4.1</commons-collections4.version>
<joda-time.version>2.9.6</joda-time.version>
<lombok.version>1.16.10</lombok.version>
</properties>
</project>

View File

@ -0,0 +1,4 @@
### Relevant Articles:
- [Guide to Guava Multiset](https://www.baeldung.com/guava-multiset)

View File

@ -60,7 +60,6 @@
<properties>
<junit.jupiter.version>5.0.0-M4</junit.jupiter.version>
<junit-vintage.version>4.12.0-M4</junit-vintage.version>
<h2.version>1.4.195</h2.version>
<log4j-core.version>2.8.2</log4j-core.version>
<junit-platform-surefire-provider.version>1.0.0-M4</junit-platform-surefire-provider.version>
</properties>

View File

@ -41,7 +41,6 @@
</build>
<properties>
<jackson.version>2.9.7</jackson.version>
<log4j-core.version>2.8.2</log4j-core.version>
</properties>

View File

@ -31,9 +31,9 @@
<version>${rest-assured.version}</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<groupId>com.h2</groupId>
<artifactId>h2</artifactId>
<version>${h2database.version}</version>
<version>${h2.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
@ -62,7 +62,6 @@
<properties>
<jersey-container-servlet.version>2.25.1</jersey-container-servlet.version>
<h2database.version>1.4.195</h2database.version>
<rest-assured.version>3.0.3</rest-assured.version>
<log4j-core.version>2.8.2</log4j-core.version>
<javamelody-core.version>1.69.0</javamelody-core.version>

View File

@ -172,7 +172,7 @@
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${javax.servlet.version}</version>
<version>${javax.servlet-api.version}</version>
<scope>provided</scope>
</dependency>
@ -295,9 +295,6 @@
</profiles>
<properties>
<!-- various -->
<jstl.version>1.2</jstl.version>
<javax.servlet.version>3.1.0</javax.servlet.version>
<!-- util -->
<guava.version>19.0</guava.version>
<commons-lang3.version>3.5</commons-lang3.version>

View File

@ -64,8 +64,6 @@
<!-- Hystrix -->
<hystrix-core.version>1.5.8</hystrix-core.version>
<rxjava-core.version>0.20.7</rxjava-core.version>
<!-- Testing -->
<hamcrest-all.version>1.3</hamcrest-all.version>
<!-- maven plugins -->
<maven-war-plugin.version>2.6</maven-war-plugin.version>
<maven-resources-plugin.version>2.7</maven-resources-plugin.version>

View File

@ -7,3 +7,6 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
### Relevant Articles:
- [Mapping Multiple JSON Fields to a Single Java Field](https://www.baeldung.com/json-multiple-fields-single-java-field)
- [How to Process YAML with Jackson](https://www.baeldung.com/jackson-yaml)
- [Working with Tree Model Nodes in Jackson](https://www.baeldung.com/jackson-json-node-tree-model)

View File

@ -0,0 +1,62 @@
package com.baeldung.jackson.node;
import java.util.Iterator;
import java.util.Map.Entry;
import com.fasterxml.jackson.databind.JsonNode;
public class JsonNodeIterator {
private static final String NEW_LINE = "\n";
private static final String FIELD_DELIMITER = ": ";
private static final String ARRAY_PREFIX = "- ";
private static final String YAML_PREFIX = " ";
public String toYaml(JsonNode root) {
StringBuilder yaml = new StringBuilder();
processNode(root, yaml, 0);
return yaml.toString();
}
private void processNode(JsonNode jsonNode, StringBuilder yaml, int depth) {
if (jsonNode.isValueNode()) {
yaml.append(jsonNode.asText());
}
else if (jsonNode.isArray()) {
for (JsonNode arrayItem : jsonNode) {
appendNodeToYaml(arrayItem, yaml, depth, true);
}
}
else if (jsonNode.isObject()) {
appendNodeToYaml(jsonNode, yaml, depth, false);
}
}
private void appendNodeToYaml(JsonNode node, StringBuilder yaml, int depth, boolean isArrayItem) {
Iterator<Entry<String, JsonNode>> fields = node.fields();
boolean isFirst = true;
while (fields.hasNext()) {
Entry<String, JsonNode> jsonField = fields.next();
addFieldNameToYaml(yaml, jsonField.getKey(), depth, isArrayItem && isFirst);
processNode(jsonField.getValue(), yaml, depth+1);
isFirst = false;
}
}
private void addFieldNameToYaml(StringBuilder yaml, String fieldName, int depth, boolean isFirstInArray) {
if (yaml.length()>0) {
yaml.append(NEW_LINE);
int requiredDepth = (isFirstInArray) ? depth-1 : depth;
for(int i = 0; i < requiredDepth; i++) {
yaml.append(YAML_PREFIX);
}
if (isFirstInArray) {
yaml.append(ARRAY_PREFIX);
}
}
yaml.append(fieldName);
yaml.append(FIELD_DELIMITER);
}
}

View File

@ -0,0 +1,37 @@
package com.baeldung.jackson.node;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import org.junit.Test;
import com.fasterxml.jackson.databind.JsonNode;
public class JsonNodeIteratorUnitTest {
private JsonNodeIterator onTest = new JsonNodeIterator();
private static String expectedYaml = "name: \n" +
" first: Tatu\n" +
" last: Saloranta\n" +
"title: Jackson founder\n" +
"company: FasterXML\n" +
"pets: \n" +
"- type: dog\n" +
" number: 1\n" +
"- type: fish\n" +
" number: 50";
@Test
public void givenANodeTree_whenIteratingSubNodes_thenWeFindExpected() throws IOException {
final JsonNode rootNode = ExampleStructure.getExampleRoot();
String yaml = onTest.toYaml(rootNode);
System.out.println(yaml.toString());
assertEquals(expectedYaml, yaml);
}
}

View File

@ -0,0 +1,18 @@
{
"name": {
"first": "Tatu",
"last": "Saloranta"
},
"title": "Jackson founder",
"company": "FasterXML",
"pets": [
{
"type": "dog",
"number": 1
},
{
"type": "fish",
"number": 50
}
]
}

View File

@ -15,7 +15,6 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Jackson JSON Tutorial](http://www.baeldung.com/jackson)
- [Jackson Working with Maps and nulls](http://www.baeldung.com/jackson-map-null-values-or-null-key)
- [Jackson Decide What Fields Get Serialized/Deserialized](http://www.baeldung.com/jackson-field-serializable-deserializable-or-not)
- [Working with Tree Model Nodes in Jackson](http://www.baeldung.com/jackson-json-node-tree-model)
- [Jackson vs Gson](http://www.baeldung.com/jackson-vs-gson)
- [XML Serialization and Deserialization with Jackson](http://www.baeldung.com/jackson-xml-serialization-and-deserialization)
- [More Jackson Annotations](http://www.baeldung.com/jackson-advanced-annotations)

View File

@ -1,10 +0,0 @@
{
"name":
{
"first": "Tatu",
"last": "Saloranta"
},
"title": "Jackson founder",
"company": "FasterXML"
}

View File

@ -1,2 +1,3 @@
## Relevant Articles:
- [Map of Primitives in Java](https://www.baeldung.com/java-map-primitives)
- [Copying a HashMap in Java](https://www.baeldung.com/java-copy-hashmap)

View File

@ -1,2 +1,3 @@
## Relevant Articles:
- [Converting Between LocalDate and XMLGregorianCalendar](https://www.baeldung.com/java-localdate-to-xmlgregoriancalendar)
- [Convert Time to Milliseconds in Java](https://www.baeldung.com/java-time-milliseconds)

View File

@ -53,7 +53,7 @@
<artifactItem>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2-version}</version>
<version>${h2.version}</version>
<type>jar</type>
<outputDirectory>
${project.build.directory}/liberty/wlp/usr/servers/defaultServer/lib/global
@ -64,8 +64,4 @@
</plugin>
</plugins>
</build>
<properties>
<h2-version>1.4.197</h2-version>
</properties>
</project>

View File

@ -53,7 +53,7 @@
<artifactItem>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2-version}</version>
<version>${h2.version}</version>
<type>jar</type>
<outputDirectory>
${project.build.directory}/liberty/wlp/usr/servers/defaultServer/lib/global
@ -64,8 +64,4 @@
</plugin>
</plugins>
</build>
<properties>
<h2-version>1.4.197</h2-version>
</properties>
</project>

View File

@ -72,7 +72,6 @@
<javaee-version>8.0</javaee-version>
<liberty-maven-plugin.version>2.3</liberty-maven-plugin.version>
<openliberty-runtime.version>18.0.0.1</openliberty-runtime.version>
<h2-version>1.4.197</h2-version>
<maven-war-plugin.version>3.2.2</maven-war-plugin.version>
</properties>

View File

@ -38,7 +38,7 @@
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh-generator-annprocess.version}</version>
<version>${jmh-generator.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
@ -127,8 +127,6 @@
<org.slf4j.version>1.7.21</org.slf4j.version>
<logback.version>1.1.7</logback.version>
<jmh-core.version>1.19</jmh-core.version>
<jmh-generator-annprocess.version>1.19</jmh-generator-annprocess.version>
<maven-surefire-plugin.version>2.21.0</maven-surefire-plugin.version>
<maven-javadoc-plugin.version>3.0.0-M1</maven-javadoc-plugin.version>

View File

@ -18,12 +18,12 @@
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${jmh.version}</version>
<version>${jmh-core.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
<version>${jmh-generator.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
@ -44,7 +44,6 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<jmh.version>1.21</jmh.version>
<assertj.version>3.11.1</assertj.version>
</properties>
</project>

View File

@ -18,12 +18,12 @@
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${jmh.version}</version>
<version>${jmh-core.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
<version>${jmh-generator.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
@ -106,7 +106,6 @@
<properties>
<!-- util -->
<jmh.version>1.21</jmh.version>
<commons-lang3.version>3.5</commons-lang3.version>
<vavr.version>0.9.0</vavr.version>
<protonpack.version>1.15</protonpack.version>

4
java-strings-2/README.MD Normal file
View File

@ -0,0 +1,4 @@
## Relevant Articles
- [Java Localization Formatting Messages](https://www.baeldung.com/java-localization-messages-formatting)
- [Check If a String Contains a Substring](https://www.baeldung.com/java-string-contains-substring)

View File

@ -83,7 +83,7 @@
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>${hamcrest-library.version}</version>
<version>${org.hamcrest.version}</version>
<scope>test</scope>
</dependency>
@ -136,12 +136,10 @@
<commons-codec.version>1.10</commons-codec.version>
<!-- testing -->
<assertj.version>3.6.1</assertj.version>
<jmh-core.version>1.19</jmh-core.version>
<icu4j.version>61.1</icu4j.version>
<guava.version>27.0.1-jre</guava.version>
<emoji-java.version>4.0.0</emoji-java.version>
<junit-jupiter-api.version>5.3.1</junit-jupiter-api.version>
<hamcrest-library.version>1.3</hamcrest-library.version>
<passay.version>1.3.1</passay.version>
<commons-text.version>1.4</commons-text.version>
<ahocorasick.version>0.4.0</ahocorasick.version>

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 })));
}
}

Some files were not shown because too many files have changed in this diff Show More