Testing jpa entity classes - error Transaction is required - java

Based on an archetype i created a java ee app. There is an included arquillian test that runs fine. it just calls a method on a #Stateless bean that persists an pre-made entity.
now i added some entity with some relations and i wrote a test for them. But on peristing any entity i get
Transaction is required to perform this operation (either use a transaction or extended persistence context)
I think i need to mark the testmethod with #Transactional but it seems not to be in class path.
Manually invoking the transaction on injected EntityManager yields another error.
So how to correctly setup such tests and dependencies.
EDIT As Grzesiek D. suggested here are some details. this is the entity (the one thta links others):
#Entity
public class Booking implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* internal id.
*/
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", updatable = false, nullable = false)
private Long id;
/**
* Used for optimistic locking.
*/
#Version
#Column(name = "version")
private int version;
/**
* A booking must have a project related.
*/
#ManyToOne
#JoinColumn(name = "project_id")
#NotNull
private Project project;
/**
* A booking must have an owner.
*/
#ManyToOne
#JoinColumn(name = "user_id")
#NotNull
private User owner;
/**
* A booking always has a start time.
*/
#Column
#NotNull
private Timestamp start;
/**
* A booking always has an end time.
*/
#Column
#NotNull
private Timestamp end;
/**
*
* #return true if start is befor end. false otherwise (if equal or after end).
*/
#AssertTrue(message = "Start must before end.")
public final boolean isStartBeforeEnd() {
return start.compareTo(end) < 0;
}
/**
* #return the id
*/
public final Long getId() {
return id;
}
/**
* #param id
* the id to set
*/
public final void setId(final Long id) {
this.id = id;
}
/**
* #return the version
*/
public final int getVersion() {
return version;
}
/**
* #param version
* the version to set
*/
public final void setVersion(final int version) {
this.version = version;
}
/**
* #return the project
*/
public final Project getProject() {
return project;
}
/**
* #param project
* the project to set
*/
public final void setProject(final Project project) {
this.project = project;
}
/**
* #return the owner
*/
public final User getOwner() {
return owner;
}
/**
* #param owner
* the owner to set
*/
public final void setOwner(final User owner) {
this.owner = owner;
}
/**
* #return the start
*/
public final Timestamp getStart() {
return start;
}
/**
* #param start
* the start to set
*/
public final void setStart(final Timestamp start) {
this.start = start;
}
/**
* #return the end
*/
public final Timestamp getEnd() {
return end;
}
/**
* #param end
* the end to set
*/
public final void setEnd(final Timestamp end) {
this.end = end;
}
//hashCode, equals, toString omitted here
}
Here is the test:
#RunWith(Arquillian.class)
public class BookingTest {
#Deployment
public static Archive<?> createDeployment() {
return ArquillianContainer.addClasses(Resources.class, Booking.class, Project.class, User.class);
}
#Inject
private EntityManager em;
#Test
public void createBooking() {
Booking booking = new Booking();
booking.setStart(new Timestamp(0));
booking.setEnd(new Timestamp(2));
User user = new User();
user.setName("Klaus");
booking.setOwner(user);
Project project = new Project();
project.setName("theOne");
project.setDescription("blub");
booking.setProject(project);
em.persist(booking);
System.out.println("here");
}
}
And here the exception:
javax.persistence.TransactionRequiredException: JBAS011469: Transaction is required to perform this operation (either use a transaction or extended persistence context)
I know it will work if i create a #Stateless bean and encapsulate the persist there but i want a direct test of entity's validation and i need a playground to evolve the data model.

In order to have transaction support in Arquillian tests you will need to bring in extension which enables this feature. In your case jta dependency should do the job.
<dependency>
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-transaction-jta</artifactId>
<scope>test</scope>
</dependency>
In addition, if you are using JBoss, you will need to provide its JNDI for UserTranscation, so put following section in your arquillian.xml:
<?xml version="1.0" ?>
<arquillian xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://jboss.org/schema/arquillian" xsi:schemaLocation="http://jboss.org/schema/arquillian
http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<extension qualifier="transaction">
<property name="manager">java:jboss/UserTransaction</property>
</extension>
</arquillian>
This way you can use #Transactional which comes from this extension's API.

Related

How I can save information when I get exception in jpa

I've project with spring, spring-boot and JPA.
When a user tries to log in I want to register activity in a binnacle.
The authentication is with LDAP
I have a new class called LoginActivity and implement an interface with only one method to save activity with annotation #Component and my method where a want to save information when user put credentials wrong I have annotation
#Transactional(propagation = Propagation.REQUIRES_NEW)
And I have another method where I try to save information in my database
I debug my code and it looks good and the process finished well.
But when I saw my database I don't see anything
I use DTO objects between classes
My method authentication:
#Override
#Transactional
public Authentication authenticate(Authentication authentication) {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
List<GrantedAuthority> authorities = (List<GrantedAuthority>) authentication.getAuthorities();
...
context = connect(user, password);//where authentication did
My DTO class, I use lombok
#Data
#Builder
public class LoginDTO {
private String user;
private String tracking;
private Map<String, Boolean> roles;
private String name;
private String lastName;
private boolean loginSuccess;
private String ipAddress;
}
I set every value in my class DTO
LoginDTO loginDTO = LoginDTO.builder()
.loginSuccess(true)
.tracking(tracking)
.lastName(lastName)
.name(name)
.roles(roles)
.user(user)
.ipAddress(httpServletRequest.getRemoteAddr())
.build();
loginActivity.saveLoginActivity(LoginDTO);
My interface
#FunctionalInterface
public interface LoginActivity {
public void saveLoginActivity(LoginDTO loginDTO);
}
My class than implement interface
#Component
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class LoginActivityImpl implements LoginActivity {
My entity
#Entity(name = "activity_desk_control")
#Setter
#Getter
public class ActivityDeskControlEntity {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Basic(optional = false)
#Size(max = 255)
#Column(name = "id")
private String id;
#ManyToOne
#JoinColumn(name = "id_user_desk")
private DeskUserLogEntity idUserDesk;
#Column(name = "creation_date")
private Date creationDate;
#Column(name = "id_tracking")
private String idTracking;
#ManyToOne
#JoinColumn(name = "id_service_desk_control")
private ServiceDeskControlEntity idServiceDeskControl;
#Column(name = "params")
#Lob
private String params;
#Column(name = "url")
private String url;
#Column(name = "ip_address")
private String ipAddress;
#Column(name = "login_success")
private int loginSuccess;
#Column(name = "logout")
private int logout;
#Column(name = "logout_date")
private Date logoutDate;
}
My method where I save activity if authentication was well
public void saveMultipart(ActivityDeskControlEntity activityDeskControlEntity) {
this.activityDeskControlRepository.save(activityDeskControlEntity);
}
My method where I save activity if authentication was wrong
#Transactional(propagation = Propagation.REQUIRES_NEW)
public SimpleResponse saveMultipartLoginFail(ActivityDeskControlEntity activityDeskControlEntity) {
this.activityDeskControlRepository.save(activityDeskControlEntity);
}
Have you some idea how I can save information if I got an exception in JPA?
I look some links like this but not work.
My database is Oracle 19c
Update 1
The exception I get when I put credentials wrong is
javax.naming.AuthenticationException: [LDAP: error code 49 - Invalid Credentials]
In this scenario I want to save information the login fail.
Update 2
In the scenario that throws an exception is
context = connect(user, password);
For default LDAP throw an exception when user and password are wrong in consequence in this exception I want to save.
Update 3
I saw in documentation says:
Any RuntimeException or Error triggers rollback, and any checked
Exception does not.
When the user put credentials wrong throw an exception that extends RuntimeException
import org.springframework.security.core.AuthenticationException;
/**
* Thrown if an authentication request is rejected because the credentials are invalid.
* For this exception to be thrown, it means the account is neither locked nor disabled.
*
* #author Ben Alex
*/
public class BadCredentialsException extends AuthenticationException {
// ~ Constructors
// ===================================================================================================
/**
* Constructs a <code>BadCredentialsException</code> with the specified message.
*
* #param msg the detail message
*/
public BadCredentialsException(String msg) {
super(msg);
}
/**
* Constructs a <code>BadCredentialsException</code> with the specified message and
* root cause.
*
* #param msg the detail message
* #param t root cause
*/
public BadCredentialsException(String msg, Throwable t) {
super(msg, t);
}
}
/**
* Abstract superclass for all exceptions related to an {#link Authentication} object
* being invalid for whatever reason.
*
* #author Ben Alex
*/
public abstract class AuthenticationException extends RuntimeException {
// ~ Constructors
// ===================================================================================================
/**
* Constructs an {#code AuthenticationException} with the specified message and root
* cause.
*
* #param msg the detail message
* #param t the root cause
*/
public AuthenticationException(String msg, Throwable t) {
super(msg, t);
}
/**
* Constructs an {#code AuthenticationException} with the specified message and no
* root cause.
*
* #param msg the detailed message
*/
public AuthenticationException(String msg) {
super(msg);
}
}
I tried to change type of exception, but I couldn't, why? spring security to expected BadCredentialsException and not my own BadCredentialsException.
Are there any way to achieve that?
The simplest approach would be a try catch statement since the Stacktrace for the exception is missing in your question I ave to guess that your exception is thrown in line
context = connect(user, password);//where authentication did
A solution would then be
try {
context = connect(user, password);//where authentication did
} catch (AuthenticationException e) {
log.error("User could not autheticate");
someRepository.save(CustomErrorObject);
someOtherCustomSaveMethod();
throw e;
}
the error behavior is still the same since the exception is re thrown in the catch statement, but the save code before can be executed.

Hibernate looking for column in wrong table

I have this query that works in native SQL and Hibernate in Java.
It breaks with error that says
could not resolve property: entityName …
(or amount) when I use pageable to sort results for one of those two columns.
Also Hibernate fails to map items to Page<McConsumerBalanceEntity> and returns pageimpl of objects so I am using List<Object[]> to map items manually which works.
Hibernate version is 5.3.7. Database is PostgreSQL 10.5. Spring Boot is 2.1.0
#Query(
value = "select csr.id, csr.firstName, csr.lastName, " +
"sum (case " +
"when acs.type = 'PAYMENT' then acs.amount " +
"else -acs.amount " +
"end) as amount, " +
"me.id as entityId, " +
"me.name as entityName " +
"from McConsumerEntity csr, EbAccountConsumerEntity acs, McEntity me " +
"where csr.idMcEntity in :childEntityIds " +
"and csr.idMcEntity = me.id " +
"and csr.id = acs.idMcConsumer " +
"and amount > 0 " +
"group by csr.id, me.id, me.name ")
public class McConsumerBalanceEntityGenerated implements Serializable {
private static final long serialVersionUID = 217L;
#Id
#GeneratedValue(generator = "sequence_null", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "sequence_null",
sequenceName = "sequence_null", allocationSize = 100)
protected Long id;
#Column(name = "amount")
protected BigDecimal amount;
#Column(name = "entity_id")
protected Long entityId;
#Column(name = "entity_name")
protected String entityName;
#Column(name = "first_name")
protected String firstName;
#Column(name = "last_name")
protected String lastName;
//---------------------------------------------------------------------
public McConsumerBalanceEntityGenerated() {
super();
}
/*
//---------------------------------------------------------------------
private McConsumerBalanceEntity(Builder builder) {
this.id = builder.id;
}
*/
//---------------------------------------------------------------------
public Long getId() {
return id;
}
/**
* Access method for the amount property.
*
* #return the current value of the amount property
*/
public BigDecimal getAmount() {
return this.amount;
}
/**
* Sets the value of the amount property.
*
* #param aAmount the new value of the version property
*/
public void setAmount(BigDecimal aAmount) {
this.amount = aAmount;
}
/**
* Access method for the entityId property.
*
* #return the current value of the entityId property
*/
public Long getEntityId() {
return this.entityId;
}
/**
* Sets the value of the entityId property.
*
* #param aEntityId the new value of the version property
*/
public void setEntityId(Long aEntityId) {
this.entityId = aEntityId;
}
/**
* Access method for the entityName property.
*
* #return the current value of the entityName property
*/
public String getEntityName() {
return this.entityName;
}
/**
* Sets the value of the entityName property.
*
* #param aEntityName the new value of the version property
*/
public void setEntityName(String aEntityName) {
this.entityName = aEntityName;
}
/**
* Access method for the firstName property.
*
* #return the current value of the firstName property
*/
public String getFirstName() {
return this.firstName;
}
/**
* Sets the value of the firstName property.
*
* #param aFirstName the new value of the version property
*/
public void setFirstName(String aFirstName) {
this.firstName = aFirstName;
}
/**
* Access method for the lastName property.
*
* #return the current value of the lastName property
*/
public String getLastName() {
return this.lastName;
}
/**
* Sets the value of the lastName property.
*
* #param aLastName the new value of the version property
*/
public void setLastName(String aLastName) {
this.lastName = aLastName;
}
/* //---------------------------------------------------------------------
public static class Builder {
private Long id;
public Builder setId(Long id) {
this.id = id;
return this;
}
public McConsumerBalanceEntity build() {
return new McConsumerBalanceEntity(this);
}
}*/
}
As the error clearly states that could not resolve property: entityName, which means the column does not exists in the Entity which it is trying to fetch. And I can observe that in your SQL native query, You are trying to fetch it from me.Name and as per the entity you have provided it is present in McConsumerBalanceEntityGenerated. So try joining this Entity and fetch the entityName from this table/Entity.
You are not saying which Hibernate version your are using or what database, so everyone here has to guess about these questions and many more. If you ever want to receive good answers, consider giving more details in your questions or pay a consultant to do the work for you. The way you are asking questions here is as if you were asking a mechanic "My Ford makes a strange noise when driving fast, what's the problem?".
Having said that, I'll start guessing by assuming you are using Oracle. Maybe you are running into an issue similar to the following one: https://discourse.hibernate.org/t/issues-in-migrating-from-hibernate-5-3-3-to-5-3-4/5679/2
Also Hibernate fails to map items to Page and returns pageimpl of objects so I am using List<Object[]> to map items manually which works.
That is expected. Hibernate does not do "inference" or anything like that. If you want McConsumerBalanceEntity to be returned, then use a JPQL constructor expression.

How to load data from Database and instance the entity (Hibernate & Spring)

I would like to get objects ResponsableEntity by id from the Database where they are saved. I use Spring-boot and hibernate for the first time and the slouches on other topics don't work in my project
Here are my code :
ResponsableEntity :
#Entity
#Table(name = "responsable")
public class ResponsableEntity {
/**
* Id of the responsable
*/
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
/**
* First name of the responsable
*/
#Column(nullable=false)
private String firstName;
/**
* Lst name of the responsable
*/
#Column(nullable=false)
private String lastName;
/**
* Last latitude of the responsable position
*/
private Double latitude;
/**
* Last longitude of the responsable position
*/
private Double longitude;
/**
* All getters and setters [...]
*/
}
ResponsableDBRepository :
#Repository
public interface ResponsableDBRepository extends CrudRepository<ResponsableEntity, Long> {
}
ResponsableController (REST) :
#RestController
#RequestMapping("/responsable")
public class ResponsableController {
/**
* CRUD Repository atribut needed for the methods below
*/
private final ResponsableDBRepository responsableDBRepository;
private final ResponsableStatDBRepository responsableStatDBRepository;
/**
* Constructor
*
* #param responsableDBRepository CRUD repository for ResponsableEntity
* #param responsableStatDBRepository CRUD repository for ResponsableStatEntity
*/
#Autowired
public ResponsableController(ResponsableDBRepository responsableDBRepository, ResponsableStatDBRepository responsableStatDBRepository){
this.responsableDBRepository = responsableDBRepository;
this.responsableStatDBRepository = responsableStatDBRepository;
}
#GetMapping(path = "/get")
public #ResponseBody String getAllResponsable(){
//get object with id given
return "Returned";
}
}
I'd like that when we call this request, the entity is load from the database and an object ResponsableEntity is created with the infos saved in the database. I already tried most of the answer I found on other topics but most of the time my IDE told me he can't find the class required and it seems to be "default" classes from Hibernate and Spring
Thank you in advance for your answer !
Use this:-
ResponsableEntity responsableEntity = responsableDBRepository.findById(id);

How can I grab an item from a collection in a serializable class?

I have something like this(Very simplified version):
public class TransferData implements Serializable{
private Collection[] collections;
private String ID;
public TransferData( Collection[] collections){
this.ID = ID;
this.collections = collections;
}
public String getID(){
return ID;
}
public Collection[] getCollections(){
return collections;
}
}
This is how I usually grab an item:
//Save object in db
ContentValues values = new ContentValues();
values.put("id", td.getID());
However, I am having trouble understanding how to grab an item from a collection/array in a serializable class?
This doesn't make sense:
ContentValues values = new ContentValues();
values.put("collectionitem1", td.getCollections()); ??? //need to index the array, how?
I tried something like this:
for (int i=0; i <= td.getCollections().length; i++) {
System.out.println(i);
}
but strangely only gives me 3 indices instead of 4 indices that I have in my array but it doesn't help me. Also, my array contains strings and integers, so might be hard to index through with a foreach style loop.
Figured it out! I knew it was something about setting up going through the array incorrectly. Here's the solution:
//Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
for (Collection collection : td.getCollections()) {
values.put("reminders", collection.getNumberOfReminders());
}
I see you're using SQLite. It seems to me that you're going about this all wrong. It seems like you need to use Entity Classes:
/**
*
* #author kkennedy
*/
#Entity(name = "TransferData")
#Table(name = "TransferData")
public class TransferData implements Serializable {
#Id
#Basic(optional = false)
#Column(name = "ID", nullable = false, length = 8)
private String ID;
#Basic(optional = false)
#Column(name = "data", nullable = false, length = 8)
private String data;
/**
* Default Constructor
*/
public TransferData() {
}
/**
* Getter
*
* #return
*/
public String getID() {
return ID;
}
/**
* Setter
*
* #param ID
*/
public void setID(String ID) {
this.ID = ID;
}
/**
* Getter
*
* #return
*/
public String getData() {
return data;
}
/**
* Setter
*
* #param data
*/
public void setData(String data) {
this.data = data;
}
}
I'm sure this is not what you would actually use, but by using Entity Classes, the JDBC driver does all the work of actually putting the data into and out of the database. You just enter it into the class and then persist and query the database, as needed.
Not sure if this is the best place to start, but try here for more info: http://docs.oracle.com/javaee/5/tutorial/doc/bnbqw.html

Spring form:select not defaulting to saved object

I have a form that is representing a Role object. This role object can have one System object, which is selected via a drop-down list (form:select). It works perfectly except for one little snag: when editing the Role object the System object is not automatically selected on the list. From what I understand, it should be. Can anyone tell me why it isn't? Code is as follows:
Role class:
/**
* Represents a Role in the Database. Used for tracking purposes it allows us to
* find out what users and systems have certain roles. Role entity. #author
* MyEclipse Persistence Tools
*/
#Entity
#Table(name = "roles", catalog = "jess")
public class Role implements java.io.Serializable {
// Fields
private static final long serialVersionUID = -8599171489389401780L;
private Integer roleId;
#Valid
private System system;
...
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "SYSTEM_ID")
public System getSystem() {
return this.system;
}
public void setSystem(System system) {
this.system = system;
}
Controller:
#RequestMapping(value = "/" + MappingConstants.EDIT_ROLE + "/{id}",
method = RequestMethod.POST)
public ModelAndView getEditRoleForm(#PathVariable("id") Integer id)
{
Role r = new Role();
r.setRoleId(id);
Role role = roleService.searchAllRolesByID(r);
ModelAndView modelView = new ModelAndView(MappingConstants.ROLES_FOLDER + MappingConstants.EDIT_ROLE);
modelView.addObject(AttributeConstants.ROLE, role);
List<System> systems = systemService.searchAllSystems();
modelView.addObject(AttributeConstants.ALL_SYSTEMS, systems);
return modelView;
}
Property Editor:
public class SystemEditor extends PropertyEditorSupport
{
private final ISystemService systemService;
private static Logger logger = LogManager.getLogger(SystemEditor.class.getName());
public SystemEditor(ISystemService service)
{
super();
this.systemService = service;
}
/*
* (non-Javadoc)
* #see java.beans.PropertyEditorSupport#setAsText(java.lang.String)
*/
public void setAsText(String text) throws IllegalArgumentException
{
try
{
if(logger.isDebugEnabled())
logger.debug("System value coming in the editor as: {}", text);
System system = systemService.searchAllSystemsById(Integer.valueOf(text));
setValue(system);
}
catch (Exception e)
{
logger.error("There was an error attempting to process the System from the Editor.", e);
}
}
/*
* (non-Javadoc)
* #see java.beans.PropertyEditorSupport#getAsText()
*/
public String getAsText()
{
System system = (System) getValue();
return system.getSystemId().toString();
}
}
And jsp:
<form:form method="post" action="${contextPath}/jess/saveeditedrole" modelAttribute="role">
<h2>${role.name}</h2>
<br/><br/>
<form:errors path="system"/>
<form:label path="system">System:</form:label>
<form:select path="system">
<form:options items="${systems}" itemValue="systemId" itemLabel="fullName"/>
</form:select>
In your form:select you're using System class. Make sure this class has a proper .equals() and hashCode() methods, otherwise Spring doesn't know how to tell which System object is selected.

Categories

Resources