I have two entities working in Mater Detail pattern like i describe in:
Stackoverflow Post: jpa-eclipselink-onetomany-derived-ids-fail
The pattern works as expected with LOCAL RESOURCE, but when i try to move the example to a web environment GlassFish4.1 (JSF) with JTA, i get the following error:
Advertencia: DTX5014: Caught exception in beforeCompletion() callback:
java.lang.NullPointerException at entidades.OrderItemPK._persistence_set(OrderItemPK.java)
The source code for persistence class:
import java.util.List;
import javax.persistence.Query;
import javax.persistence.EntityManager;
import java.util.List;
import javax.persistence.Query;
import javax.persistence.EntityManager;
public abstract class AbstractFacade<T> {
private Class<T> entityClass;
protected abstract EntityManager getEntityManager();
public AbstractFacade(Class<T> entityClass) {
this.entityClass = entityClass;
}
public void create(T entity) {
getEntityManager().persist(entity);
}
public T edit(T entity) {
return getEntityManager().merge(entity);
}
public void remove(T entity) {
getEntityManager().remove(getEntityManager().merge(entity));
}
I tried with both methods create and edit. Any idea what I'm doing wrong, suggestions are welcome.
Your entity is using the basic 'long' types which do not allow null, so check that your database values are not null. If they are, a quick fix is to change the to the wrapper type "Long": http://edwin.baculsoft.com/2012/02/nullpointerexception-when-using-jpa/
If that is the case, you will need to track down how the database is being populated with null values for fields associated to the primary key.
The problem was in the PK class, change the data type int to Integer and then the error appeared on the method hashCode()
Related
I have written one aspect around a service class. In the aspect, I am doing some operation in the before section, which I would like to be rolled back if some exception occurs in the enclosed service method.
The service class is as follows:
#Service
#Transactional
class ServiceA {
...
public void doSomething() {
...
}
...
}
The aspect is as follows:
#Aspect
#Order(2)
public class TcStateManagementAspect {
...
#Around(value = "applicationServicePointcut()", argNames = "joinPoint")
public Object process(ProceedingJoinPoint joinPoint)
throws Throwable {
...
*/Before section */
do some processing and persist in DB
...
Object object = joinPoint.proceed();
...
do some post-processing
}
}
I am seeing an exception in the service method is not rolling back the DB operation in the Begin Section. I tried putting #Transactional on #Around, but it did not help.
In this context, I have gone through the following posts:
Spring #Transactional in an Aspect (AOP)
Custom Spring AOP Around + #Transactional
But I am not able to get any concrete idea regarding how to achieve this. Could anyone please help here? Thanks.
Like I said in my comment, what your around advice does must be declared transactional too. You cannot do that directly, because #Transactional internally uses Spring AOP via dynamic proxies. However, Spring AOP aspects cannot be the target of other aspects. But you can simply create a new helper #Component which you delegate your advice's action to.
Let us assume that the goal is to log the arguments of the #Transactional method targeted by your aspect. Then simply do this:
package com.example.managingtransactions;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class TxLogAspect {
private final static Logger logger = LoggerFactory.getLogger(TxLogAspect.class);
#Autowired
TxLogService txLogService;
#Pointcut(
"#annotation(org.springframework.transaction.annotation.Transactional) && " +
"!within(com.example.managingtransactions.TxLogService)"
)
public void applicationServicePointcut() {}
#Around("applicationServicePointcut()")
public Object process(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info(joinPoint.toString());
// Delegate to helper component in order to be able to use #Transactional
return txLogService.logToDB(joinPoint);
}
}
package com.example.managingtransactions;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.List;
/**
* Helper component to delegate aspect advice execution to in order to make the
* advice transactional.
* <p>
* Aspect methods themselves cannot be #Transactional, because Spring AOP aspects
* cannot be targeted by other aspects. Delegation is a simple and elegant
* workaround.
*/
#Component
public class TxLogService {
#Autowired
private JdbcTemplate jdbcTemplate;
#Transactional
public Object logToDB(ProceedingJoinPoint joinPoint) throws Throwable {
jdbcTemplate.update(
"insert into TX_LOG(MESSAGE) values (?)",
Arrays.deepToString(joinPoint.getArgs())
);
return joinPoint.proceed();
}
public List<String> findAllTxLogs() {
return jdbcTemplate.query(
"select MESSAGE from TX_LOG",
(rs, rowNum) -> rs.getString("MESSAGE")
);
}
}
See? We are passing through the joinpoint instance to the helper component's own #Transactional method, which means that the transaction is started when entering that method and committed or rolled back depending on the result of joinPoint.proceed(). I.e. what the aspect helper writes to the DB itself will also be rolled back if something goes wrong in the aspect's target method.
BTW, because I never used Spring transactions before, I simply took the example from https://spring.io/guides/gs/managing-transactions/ and added the two classes above. Before, I also added this to schema.sql:
create table TX_LOG(ID serial, MESSAGE varchar(255) NOT NULL);
Next, I added made sure that TxLogService is injected into AppRunner:
private final BookingService bookingService;
private final TxLogService txLogService;
public AppRunner(BookingService bookingService, TxLogService txLogger) {
this.bookingService = bookingService;
this.txLogService = txLogger;
}
If then at the end of AppRunner.run(String...) you add these two statements
logger.info("BOOKINGS: " + bookingService.findAllBookings().toString());
logger.info("TX_LOGS: " + txLogService.findAllTxLogs().toString());
you should see something like this at the end of the console log:
c.e.managingtransactions.AppRunner : BOOKINGS: [Alice, Bob, Carol]
c.e.managingtransactions.AppRunner : TX_LOGS: [[[Alice, Bob, Carol]]]
I.e. you see that only for the successful booking transaction a log message something was written to the DB, not for the two failed ones.
I am new to web app development. I am trying to expose the category ID:s so that I can implement "search by category" in my app.
But even after writing the below code I am not able to expose the ID:s.
I have seen some solutions, but they were of very little use to me because of the incompetence.
I am using Eclipse IDE.
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.metamodel.EntityType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;
import org.springframework.http.HttpMethod;
import com.kausar.ecommerce.entity.Product;
import com.kausar.ecommerce.entity.ProductCategory;
#Configuration
public class MyDataRestConfig implements RepositoryRestConfigurer {
private EntityManager entityManager;
#Autowired
public MyDataRestConfig(EntityManager theEntityManager) {
entityManager = theEntityManager;
}
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
HttpMethod[] theUnsupportedActions = {HttpMethod.PUT, HttpMethod.POST, HttpMethod.DELETE};
// disable HTTP methods for Product: PUT, POST and DELETE
config.getExposureConfiguration()
.forDomainType(Product.class)
.withItemExposure((metdata, httpMethods) -> httpMethods.disable(theUnsupportedActions))
.withCollectionExposure((metdata, httpMethods) -> httpMethods.disable(theUnsupportedActions));
// disable HTTP methods for ProductCategory: PUT, POST and DELETE
config.getExposureConfiguration()
.forDomainType(ProductCategory.class)
.withItemExposure((metdata, httpMethods) -> httpMethods.disable(theUnsupportedActions))
.withCollectionExposure((metdata, httpMethods) -> httpMethods.disable(theUnsupportedActions));
// call an internal helper method
exposeIds(config);
}
private void exposeIds(RepositoryRestConfiguration config) {
// expose entity ids
//get a list of all entity classes from the entity manager
Set<EntityType<?>> entities = entityManager.getMetamodel().getEntities();
//create an array of the entity types
List<Class> entityClasses = new ArrayList<>();
//get the entity types for the entities
for (EntityType tempEntityType : entities) {
entityClasses.add(tempEntityType.getJavaType());
}
//expose entity ids for the array of entity/domain types
Class[] domainTypes = entityClasses.toArray(new Class[0]);
config.exposeIdsFor(domainTypes);
}
}
just call the helper method and remove the other code :
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
exposeIds(config);
}
you need to override this method of RepositoryRestConfigurer interface :
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) {
//all code
}
it is perfectly working for me.....
CorsRegistry cors => add this as a second parameter in configureRepositoryRestConfiguration method
when I try to use Generic Dao in android Room I get this Erro :
Cannot use unbound generics in query methods. It must be bound to a type through base Dao class.
import android.arch.lifecycle.LiveData;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Delete;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.RawQuery;
import android.arch.persistence.room.Update;
import java.util.List;
#Dao
public interface BaseDaoAccess<T> {
#Insert
Long Insert(T entity);
#Update
void Update(T entity);
#Delete
void Delete(T entity);
#RawQuery
LiveData<List<T>> RowQuery(String query);
}
Due to type erasure, Java can't tell at runtime what T you mean. You can provide this information by creating a subtype that has the T bound to a specific type, such as this:
public interface CarDao extends BaseDaoAccess<Car> { }
I have to implement DAOs which use only the interfaces of the objects. Now I'm having trouble figuring out how to use the em.find()of the EntityManagerclass.
My specific question is, if it is ok to import the implementation of a class directly into the DAO like in this example:
import dao.IStreamingServerDAO;
import model.IStreamingServer;
import model.impl.StreamingServer;
import javax.persistence.EntityManager;
public class StreamingServerDAO implements IStreamingServerDAO {
protected EntityManager em;
public StreamingServerDAO(EntityManager em) {
this.em = em;
}
#Override
public IStreamingServer findById(Long id) {
return em.find(StreamingServer.class, id);
}
}
I feel like I'm hurting some privacy principles by simply importing the model.impl.StreamingServer class into the DAO.
Problem is I don't know how else I'm supposed to get the needed class for the em.find()method.
Please not that I can't change the return type of the findByIdmethod as it's defined like this by the interface. (Also this implementation right now works as expected).
So I have a sample code like this:
package biz.tugay.books10Aug.dao;
/* User: koray#tugay.biz Date: 10/08/15 Time: 22:54 */
import biz.tugay.books10Aug.model.Book;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
public class BookDaoImpl implements BookDao {
private EntityManager entityManager;
public BookDaoImpl(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Override
public void persist(Book book) {
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.persist(book);
transaction.commit();
}
}
and this is how I unit test it:
package biz.tugay.books10Aug.dao;
/* User: koray#tugay.biz Date: 10/08/15 Time: 22:56 */
import biz.tugay.books10Aug.model.Book;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class BookDaoImplTest {
#Test
public void testPersistNewBook() throws Exception {
PersistenceUtil.initalizeEntityManagerFactory();
EntityManager entityManager = PersistenceUtil.getEntityManager();
BookDao bookDao = new BookDaoImpl(entityManager);
String isbn = new SimpleDateFormat("HHmmss").format(Calendar.getInstance().getTime());
Book book = new Book();
book.setIsbn(isbn);
book.setName("Just Another Book in the DB, Volume: " + isbn);
book.setPrice(10);
book.setPublishDate(Calendar.getInstance().getTime());
book.setPublisher("002");
bookDao.persist(book);
}
}
This all works fine. My question is about OOP.
I decided that BookDaoImpl should not be responsible for getting the EntityManager. It should be the BookService 's responsibility. Why? I a do not know really.
Also, whos responsibility should be to get transaction, begin and commit? Again BookService or BookDao?
JPA Transaction should be managed on a service layer. Here's an counterexample:
consider you have a find method in your DAO layer:
public Book find(long id) {
return entityManager.find(Book.class, id);
}
And your Book class owns a collection of pages:
#OneToMany(mappedBy = "book", fetch = LAZY")
private Set<Page> pages;
public Set<Page> getPages() {
return pages;
}
If the entityManager has a lifecycle within a DAO, the call of getPages() method made from your service layer will result in lazy initialization exception
Of course in each rule there are exceptions, but in general you should manage your transaction on service layer (or repository layer depending on wording).
You can even use MANDATORY transaction demarcation attribute in your DAO layer in order to make it mandatory.
my opinion is it's ok that BookDao knows about EntityManager since it's about way of data persistence.
Regarding transaction - it's responsibility of service layer since it;s responsible for business logic implementation and transaction borders defines in business requirements. However it would be great to implement transaction management independently from persistence technology (now you are using JPA, tomorrow JDBC, later something else). Think Spring's transactions annotations could be a good example of this approach.