Pitfall:
We strongly advise not to use OData v4 in conjunction with SAPUI5, as the SAPUI5 support for OData v4 is lackluster and leads to a number of problems in practice. OData v2 however is fully supported by SAPUI5.
Pitfall:
Furthermore, we suggest using Hibernate rather than the default SAP JPA provider as your JPA implementation.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>odata</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>OlingoClassloaderFilter</filter-name>
<filter-class>com.yourpackage.web.OlingoFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OlingoClassloaderFilter</filter-name>
<url-pattern>/*</url-pattern>
<servlet-name>ODataServlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<servlet>
<servlet-name>ODataServlet</servlet-name>
<servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>org.apache.olingo.odata2.core.rest.app.ODataApplication</param-value>
</init-param>
<init-param>
<param-name>org.apache.olingo.odata2.service.factory</param-name>
<param-value>com.yourpackage.processor.AnnotationServiceFactory</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ODataServlet</servlet-name>
<url-pattern>/Data.svc/*</url-pattern>
</servlet-mapping>
</web-app>
public class AnnotationServiceFactory extends ODataServiceFactory {
private static final Location LOG = Location.getLocation(AnnotationServiceFactory.class);
/**
* Instance holder for all annotation relevant instances which should be
* used as singleton instances within the ODataApplication (ODataService)
*/
private static class AnnotationInstances {
final static String MODEL_PACKAGE = "com.yourpackage.model";
final static ODataService ANNOTATION_ODATA_SERVICE;
static {
try {
ANNOTATION_ODATA_SERVICE = createAnnotationService(MODEL_PACKAGE);
} catch (ODataApplicationException ex) {
throw new RuntimeException("Exception during sample data generation.", ex);
} catch (ODataException ex) {
throw new RuntimeException("Exception during data source initialization generation.", ex);
}
}
}
private static ODataService createAnnotationService(final String modelPackage) throws ODataException {
AnnotationEdmProvider edmProvider = new AnnotationEdmProvider(modelPackage);
PersistentDataSource dataSource = new PersistentDataSource(modelPackage);
AnnotationValueAccess valueAccess = new AnnotationValueAccess();
// Edm via Annotations and ListProcessor via AnnotationDS with
// AnnotationsValueAccess
return RuntimeDelegate.createODataSingleProcessorService(edmProvider,
new ListsProcessor(dataSource, valueAccess));
}
@Override
public ODataService createService(final ODataContext context) throws ODataException {
// Edm via Annotations and ListProcessor via AnnotationDS with
// AnnotationsValueAccess
return AnnotationInstances.ANNOTATION_ODATA_SERVICE;
}
@SuppressWarnings("unchecked")
@Override
public <T extends ODataCallback> T getCallback(final Class<T> callbackInterface) {
return (T) (callbackInterface.isAssignableFrom(ScenarioErrorCallback.class) ? new ScenarioErrorCallback()
: callbackInterface.isAssignableFrom(ODataDebugCallback.class) ? new ScenarioDebugCallback()
: super.getCallback(callbackInterface));
}
/*
* Helper classes and methods
*/
private final class ScenarioDebugCallback implements ODataDebugCallback {
@Override
public boolean isDebugEnabled() {
return true;
}
}
private class ScenarioErrorCallback implements ODataErrorCallback {
@Override
public ODataResponse handleError(final ODataErrorContext context) throws ODataApplicationException {
if (context.getHttpStatus() == HttpStatusCodes.INTERNAL_SERVER_ERROR) {
LOG.errorT("Internal Server Error: " + context.getException().toString());
}
return EntityProvider.writeErrorDocument(context);
}
}
}
@EdmEntityType(namespace = "com.yourpackage.model")
@EdmEntitySet(name = "Processes")
public class Process implements ProcessStepParent {
public static final String PROCESS_KEY = "Key";
@EdmKey
@EdmProperty(name = PROCESS_KEY)
private String key;
@EdmProperty
private String name;
@EdmProperty
private String helpText;
@EdmProperty
private String group;
@EdmNavigationProperty(toMultiplicity = Multiplicity.MANY, toType = ProcessStep.class)
private List<ProcessStep> steps;
@Override
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHelpText() {
return helpText;
}
public void setHelpText(String helpText) {
this.helpText = helpText;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public List<ProcessStep> getSteps() {
return steps;
}
public void setSteps(List<ProcessStep> steps) {
this.steps = steps;
}
}
@Entity
@Table(name = "PROCESS")
public class ProcessEntity {
@Column(name = "Process_PK")
@Id
private String id;
@Column(name = "Process_Name")
private String name;
@Column(name = "Process_Help_Text")
private String helpText;
@Column(name = "Process_Group")
private String group;
@OneToMany(mappedBy = "process", cascade = { CascadeType.ALL })
@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private List<ProcessStepEntity> steps;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHelpText() {
return helpText;
}
public void setHelpText(String helpText) {
this.helpText = helpText;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public List<ProcessStepEntity> getSteps() {
return steps;
}
public void setSteps(List<ProcessStepEntity> steps) {
this.steps = steps;
}
}
public class PersistentDataSource implements DataSource {
private static final Location LOG = Location.getLocation(PersistentDataSource.class);
/**
* Maps the name of an EDM annotated POJO (as String) to the class of the
* corresponding data store EJB interface
*/
private static final Map<String, Class<? extends AbstractDataStore<?, ?>>> edmEntityDataStoreInterfaceLookup;
static {
edmEntityDataStoreInterfaceLookup = new HashMap<String, Class<? extends AbstractDataStore<?, ?>>>();
edmEntityDataStoreInterfaceLookup.put(Process.class.getName(), ProcessDataStore.class);
edmEntityDataStoreInterfaceLookup.put(ProcessStep.class.getName(), ProcessStepDataStore.class);
}
public PersistentDataSource(final String packageToScan) throws ODataException {
ClassHelper.loadClasses(packageToScan, new ClassHelper.ClassValidator() {
@Override
public boolean isClassValid(final Class<?> c) {
return null != c.getAnnotation(org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet.class);
}
});
}
/**
* Loads the associated DataStore EJB for the EDM POJO represented by the
* EdmEntitySet.
*
* @param entitySet
* EdmEntitySet with underlying EDM POJO.
* @return DataStore EJB for underlying EDM POJO.
* @throws EdmException
*/
private static AbstractDataStore<?, ?> getDataStoreForEdmEntitySet(EdmEntitySet entitySet) throws EdmException {
String edmEntityName = mapEdmEntitySetToClassName(entitySet);
AbstractDataStore<?, ?> ds = getDataStoreForEdmEntityClass(edmEntityName);
return ds;
}
/**
* Converts EdmEntitySet to string of the fully qualified class name of the
* underlying EDM POJO. Example: EdmEntitySet for underlying class
* com.yourpackage.model.Process will be converted to
* "com.yourpackage.model.Process".
*
* @param entitySet
* EdmEntitySet with underlying EDM POJO.
* @return Fully qualified classname of kind "com.package.Pojo" of the
* underlying EDM POJO.
* @throws EdmException
*/
private static String mapEdmEntitySetToClassName(EdmEntitySet entitySet) throws EdmException {
StringBuilder sb = new StringBuilder();
sb.append(entitySet.getEntityType().getNamespace());
sb.append(".");
sb.append(entitySet.getEntityType().getName());
return sb.toString();
}
private static AbstractDataStore<?, ?> getDataStoreForEdmEntityClass(String edmEntityName) {
Class<? extends AbstractDataStore<?, ?>> dataStoreInterface = edmEntityDataStoreInterfaceLookup
.get(edmEntityName);
return getDataStoreBean(dataStoreInterface);
}
private static AbstractDataStore<?, ?> getDataStoreBean(
Class<? extends AbstractDataStore<?, ?>> dataStoreInterface) {
return ServiceLocator.getServiceInstance(dataStoreInterface, EarDc.ODATA_EAR, EjbDc.ODATA_EJB);
}
@Override
public List<?> readData(EdmEntitySet entitySet)
throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
AbstractDataStore<?, ?> ds = getDataStoreForEdmEntitySet(entitySet);
return ds.read();
}
@Override
public Object readData(EdmEntitySet entitySet, Map<String, Object> keys)
throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
AbstractDataStore<?, ?> ds = getDataStoreForEdmEntitySet(entitySet);
Object result = ds.read(keys);
return result;
}
@Override
public Object readData(EdmFunctionImport function, Map<String, Object> parameters, Map<String, Object> keys)
throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
throw new ODataNotImplementedException(ODataNotImplementedException.COMMON);
}
@Override
public Object readRelatedData(EdmEntitySet sourceEntitySet, Object sourceData, EdmEntitySet targetEntitySet,
Map<String, Object> targetKeys)
throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
AbstractDataStore<?, ?> sourceDs = getDataStoreForEdmEntitySet(sourceEntitySet);
AbstractDataStore<?, ?> targetDs = getDataStoreForEdmEntitySet(targetEntitySet);
Object result = targetDs.readRelatedData(sourceDs.getDataTypeClass(), sourceData, targetDs.getDataTypeClass(),
targetKeys);
return result;
}
@Override
public BinaryData readBinaryData(EdmEntitySet entitySet, Object mediaLinkEntryData)
throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
throw new ODataNotImplementedException(ODataNotImplementedException.COMMON);
}
@Override
public Object newDataObject(EdmEntitySet entitySet)
throws ODataNotImplementedException, EdmException, ODataApplicationException {
AbstractDataStore<?, ?> ds = getDataStoreForEdmEntitySet(entitySet);
return ds.createInstance();
}
@Override
public void writeBinaryData(EdmEntitySet entitySet, Object mediaLinkEntryData, BinaryData binaryData)
throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
throw new ODataNotImplementedException(ODataNotImplementedException.COMMON);
}
@Override
public void deleteData(EdmEntitySet entitySet, Map<String, Object> keys)
throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
AbstractDataStore<?, ?> ds = getDataStoreForEdmEntitySet(entitySet);
ds.delete(keys);
}
@Override
public void createData(EdmEntitySet entitySet, Object data)
throws ODataNotImplementedException, EdmException, ODataApplicationException {
throw new ODataNotImplementedException(ODataNotImplementedException.COMMON);
}
@Override
public void deleteRelation(EdmEntitySet sourceEntitySet, Object sourceData, EdmEntitySet targetEntitySet,
Map<String, Object> targetKeys)
throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
throw new ODataNotImplementedException(ODataNotImplementedException.COMMON);
}
@Override
public void writeRelation(EdmEntitySet sourceEntitySet, Object sourceData, EdmEntitySet targetEntitySet,
Map<String, Object> targetKeys)
throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
throw new ODataNotImplementedException(ODataNotImplementedException.COMMON);
}
}
public interface AbstractDataStore<T, K> {
public Class<?> getDataTypeClass();
public String getEntityTypeName();
public T createInstance();
public K mapEdmObjectToJpaEntity(T object);
public T mapJpaEntityToEdmObject(K entity);
public List<K> mapEdmObjectsToJpaEntities(Collection<T> objects);
public List<T> mapJpaEntitiesToEdmObjects(Collection<K> entities);
public T read(final Map<String, Object> keys);
public List<T> read();
public T create(final T obj);
public T update(final T obj);
public void delete(final Map<String, Object> keys);
public void delete(final T obj);
/**
* Returns the field of type <code>targetTypeClass</code> that
* <code>relatedObject</code> of type <code>relatedTypeClass</code> has. The
* contract for reading relations with this method is as follows: If for
* example the relatedObject is of type <code>A</code>, that has a
* one-to-many relationship to <code>B</code> through a List of the target
* type <code>B</code> and <code>B</code> is mapped bi-directional with a
* single object field of type <code>A</code>, then to get
*
* (1) the related List of <code>B</code>, you call this method on the
* DataStore for <code>B</code> and pass <code>A</code> as related class
*
* (2) the related parent object for <code>A</code>, you call this method on
* the DataStore for <code>A</code> and pass <code>B</code> as related
* class.
*
* That is to say, that you always <b>call this method on the DataStore for
* the target class</b>, passing the "parent" object as the
* <code>relatedObject</code>.
*
* @param relatedTypeClass
* @param relatedObject
* @param targetTypeClass
* @param targetKeys
* @return
*/
public Object readRelatedData(Class<?> relatedTypeClass, Object relatedObject, Class<?> targetTypeClass,
Map<String, Object> targetKeys);
}
/**
*
* @param <EdmType>
* The type of the associated EDM object (i.e. a class annotated with
* {@link org.apache.olingo.odata2.api.annotation.edm.EdmEntityType}}
* @param <EntityType>
* The type of the corresponding JPA entity (i.e. a class annotated
* with {@link javax.persistence.Entity}
* @param <EntityKeyType>
* The type of the primary key of the JPA entity
*/
public abstract class AbstractDataStoreBean<EdmType, EntityType, EntityKeyType> {
protected static final AnnotationHelper ANNOTATION_HELPER = new AnnotationHelper();
public abstract Class<?> getDataTypeClass();
public abstract Class<?> getEntityClass();
public String getEntityTypeName() {
return ANNOTATION_HELPER.extractEntityTypeName(getDataTypeClass());
}
@SuppressWarnings("unchecked")
public EdmType createInstance() {
try {
return (EdmType) getDataTypeClass().newInstance();
} catch (InstantiationException e) {
throw new AnnotationRuntimeException("Unable to create instance of class '" + getDataTypeClass() + "'.", e);
} catch (IllegalAccessException e) {
throw new AnnotationRuntimeException("Unable to create instance of class '" + getDataTypeClass() + "'.", e);
}
}
protected abstract GenericDao<EntityType, EntityKeyType> getDao();
public abstract List<Class<?>> getRelatedEdmEntityTypeClasses();
protected abstract EntityKeyType mapKeyMapToJpaEntityKey(Map<String, Object> keyMap);
/**
* Maps an EDM object to its corresponding JPA entity.
*
* @param The
* EDM object
* @return The corresponding JPA entity object
*/
public abstract EntityType mapEdmObjectToJpaEntity(EdmType object);
public List<EntityType> mapEdmObjectsToJpaEntities(Collection<EdmType> objects) {
if (objects == null || objects.isEmpty()) {
return Collections.<EntityType>emptyList();
}
List<EntityType> result = objects.stream().map(object -> mapEdmObjectToJpaEntity(object))
.collect(Collectors.toList());
return result;
}
public List<EdmType> mapJpaEntitiesToEdmObjects(Collection<EntityType> entities) {
if (entities == null || entities.isEmpty()) {
return Collections.<EdmType>emptyList();
}
List<EdmType> result = entities.stream().map(entity -> mapJpaEntityToEdmObject(entity))
.collect(Collectors.toList());
return result;
}
/**
* Maps a JPA entity to its corresponding EDM object.
*
* @param entity
* The JPA entity object
* @return The corresponding EDM object.
*/
public abstract EdmType mapJpaEntityToEdmObject(EntityType entity);
private void assertKeyMapContainsKey(Map<String, Object> keyMap, String key) {
if (!keyMap.containsKey(key)) {
throw new IllegalArgumentException("Key map for EDM object must contain key named \"" + key + "\"");
}
}
/**
* Ensures that <code>keyMap</code> contains entries for all keys in
* <code>keys</code>. If a key in <code>keys</code> does not exist in the
* map, an {@link IllegalArgumentException} is raised.
*
* @param keyMap
* The map to check for keys
* @param keys
* The list of keys that must be in <code>keyMap</code>
*/
protected void assertKeyMapContainsKeys(Map<String, Object> keyMap, List<String> keys) {
keys.forEach((key) -> assertKeyMapContainsKey(keyMap, key));
}
protected void validateRelatedTypeClasses(Class<?> relatedTypeClass, Class<?> targetTypeClass) {
validateTargetTypeClass(targetTypeClass);
validateRelatedTypeClass(relatedTypeClass);
}
protected void validateTargetTypeClass(Class<?> targetTypeClass) {
if (targetTypeClass != getDataTypeClass()) {
throw new IllegalArgumentException("This DataStore can only return EDM entities of type "
+ getDataTypeClass().getName()
+ "! Please set the targetTypeClass parameter accordingly, or call the readRelatedData method on the correct DataStore.");
}
}
protected void validateRelatedTypeClass(Class<?> relatedTypeClass) {
if (!(getRelatedEdmEntityTypeClasses().contains(relatedTypeClass))) {
throw new IllegalArgumentException("The EDM entity " + getDataTypeClass().getName()
+ " of this DataStore is not related to the EDM entity " + relatedTypeClass.getName() + "!");
}
}
public abstract Object readRelatedData(Class<?> relatedTypeClass, Object relatedObject);
public Object readRelatedData(Class<?> relatedTypeClass, Object relatedObject, Class<?> targetTypeClass,
Map<String, Object> targetKeys) {
validateRelatedTypeClasses(relatedTypeClass, targetTypeClass);
// If the target object is determined by a (composite) key, we simply
// load it by this primary key
if (!targetKeys.isEmpty()) {
return read(targetKeys);
}
// Otherwise we need to load it by its association to the relatedObject
Object result = readRelatedData(relatedTypeClass, relatedObject);
if (result == null) {
throw new IllegalStateException(
"Ensure that the method getRelatedDataTypeClasses of this DataStore is correct!");
}
return result;
}
public List<EdmType> read() {
List<EntityType> jpaEntities = getDao().findAll();
List<EdmType> mappedEdmObjects = mapJpaEntitiesToEdmObjects(jpaEntities);
return mappedEdmObjects;
}
public EdmType read(EntityKeyType primaryKey) {
Optional<EntityType> optionalEntity = Optional.ofNullable(getDao().find(primaryKey));
return (optionalEntity.isPresent() ? mapJpaEntityToEdmObject(optionalEntity.get()) : null);
}
/**
* Load an Olingo EDM object by a primary key that consists of all fields
* annotated with
* {@link org.apache.olingo.odata2.api.annotation.edm.EdmKey}.
*
* Example: Suppose an EDM object has two fields <code>key1</code> and
* <code>key2</code> annotated with
* {@link org.apache.olingo.odata2.api.annotation.edm.EdmKey}. Then, the
* <code>keys</code> map should contain two keys "Key1" and "Key2" (note the
* capitalization). This method converts the map of keys to a primary key of
* the corresponding JPA entity and loads the entity with this primary key
* from the database.
*
* @param keys
* Map with keyvalues for each field annotated with
* {@link org.apache.olingo.odata2.api.annotation.edm.EdmKey}.
* @return The EDM object with the (composite) key represented by the
* <code>keys</code> map, iff such an entity with this key exists in
* the database.
*/
public EdmType read(Map<String, Object> keys) {
EntityKeyType key = mapKeyMapToJpaEntityKey(keys);
return read(key);
}
public EdmType create(EdmType obj) {
EntityType mappedEntity = mapEdmObjectToJpaEntity(obj);
EntityType persistentEntity = getDao().save(mappedEntity);
EdmType mappedEdmObject = mapJpaEntityToEdmObject(persistentEntity);
return mappedEdmObject;
}
public EdmType update(EdmType obj) {
EntityType mappedEntity = mapEdmObjectToJpaEntity(obj);
EntityType persistentEntity = getDao().update(mappedEntity);
EdmType mappedEdmObject = mapJpaEntityToEdmObject(persistentEntity);
return mappedEdmObject;
}
public void delete(Map<String, Object> keys) {
EntityKeyType key = mapKeyMapToJpaEntityKey(keys);
Optional<EntityType> optionalEntity = Optional.ofNullable(getDao().find(key));
optionalEntity.ifPresent(entity -> getDao().remove(entity));
}
public void delete(EdmType obj) {
EntityType mappedEntity = mapEdmObjectToJpaEntity(obj);
getDao().remove(mappedEntity);
}
}
@Local
public interface ProcessDataStore extends AbstractDataStore<Process, ProcessEntity> {
}
@Stateless
public class ProcessDataStoreBean extends AbstractDataStoreBean<Process, ProcessEntity, String>
implements ProcessDataStore {
@EJB
ProcessEntityDao processDao;
@EJB
ProcessStepDataStore processStepDS;
@Override
public Class<?> getDataTypeClass() {
return Process.class;
}
@Override
public Class<?> getEntityClass() {
return ProcessEntity.class;
}
@Override
public Process createInstance() {
return (Process) super.createInstance();
}
@Override
protected GenericDao<ProcessEntity, String> getDao() {
return processDao;
}
@Override
public List<Class<?>> getRelatedEdmEntityTypeClasses() {
return Arrays.asList(ProcessStep.class);
}
@Override
protected String mapKeyMapToJpaEntityKey(Map<String, Object> keyMap) {
assertKeyMapContainsKeys(keyMap, Arrays.asList(Process.PROCESS_KEY));
String result = (String) keyMap.get(Process.PROCESS_KEY);
return result;
}
@Override
public ProcessEntity mapEdmObjectToJpaEntity(Process object) {
ProcessEntity result = new ProcessEntity();
result.setId(object.getKey());
result.setName(object.getName());
result.setGroup(object.getGroup());
result.setHelpText(object.getHelpText());
result.setSteps(processStepDS.mapEdmObjectsToJpaEntities(object.getSteps()));
return result;
}
@Override
public Process mapJpaEntityToEdmObject(ProcessEntity entity) {
Process result = new Process();
result.setKey(entity.getId());
result.setName(entity.getName());
result.setGroup(entity.getGroup());
result.setHelpText(entity.getHelpText());
result.setSteps(processStepDS.mapJpaEntitiesToEdmObjects(entity.getSteps()));
return result;
}
@Override
public Object readRelatedData(Class<?> relatedTypeClass, Object relatedObject) {
if (relatedTypeClass == ProcessStep.class) {
ProcessStep relatedProcessStep = (ProcessStep) relatedObject;
String processKey = relatedProcessStep.getProcessKey();
Process targetObject = read(processKey);
return targetObject;
}
return null;
}
}
public interface GenericDao<E, K> {
public E find(K primaryKey);
public List<E> findAll();
public E save(E entity);
public void removeAll();
public void remove(E entity);
public E update(E entity);
}
public abstract class GenericDaoBean<E, K> implements GenericDao<E, K> {
private Class<E> entityClass;
public GenericDaoBean(Class<E> entityClass) {
this.entityClass = entityClass;
}
@Override
public E find(K primaryKey) {
E entity = getEntityManager().find(entityClass, primaryKey);
return entity;
}
@Override
@SuppressWarnings("unchecked")
public List<E> findAll() {
Query q = getEntityManager().createQuery("SELECT e FROM " + entityClass.getName() + " e");
List<E> list = (List<E>) q.getResultList();
return list;
}
@Override
public E save(E entity) {
getEntityManager().persist(entity);
return entity;
}
@Override
public void removeAll() {
Query q = getEntityManager().createQuery("DELETE FROM " + entityClass.getName());
q.executeUpdate();
}
@Override
public void remove(E entity) {
getEntityManager().remove(entity);
}
@Override
public E update(E entity) {
E mergedEntity = getEntityManager().merge(entity);
return mergedEntity;
}
protected abstract EntityManager getEntityManager();
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
8 | |
5 | |
5 | |
4 | |
4 | |
4 | |
4 | |
4 | |
3 | |
3 |