OpenEntityManagerInViewFilter Not Working In Unit Test - spring

I'm writing a unit test for a controller, but when my test reaches the line where it called this method
private Predicate predicate( final Integer pid )
{
return
new Predicate()
{
public boolean evaluate( Object o )
{
ProviderAuxiliaryAccount proAux = ( ProviderAuxiliaryAccount) o;
return proAux.getProviderAccount().getId() == pid;
}
};
}
It throws a NullPointerException on this line:
return proAux.getProviderAccount().getId() == pid;
When I checked the ProviderAuxiliaryAccount object, It can not seem to retrieve its ProviderAccount property. Therefore, calling getProviderAccount().getId() will surely fire a null pointer exception. But this only happens during the unit test. I suspect that OpenEntityManagerInViewFilter is not working on the unit test.
Here are some excerpts from my java classes:
Controller Test class
#Transactional
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration( loader = CustomContextLoader.class, locations = {"/applicationContext-web-test.xml","/applicationContext-web-mail-test.xml"})
public class ControllerTest extends AbstractTransactionalJUnit4SpringContextTests
ProviderAuxiliaryAccount model
public class ProviderAuxiliaryAccount
implements Serializable
{
private static final long serialVersionUID = 1L;
private Integer id;
private Integer providerId;
#XmlTransient
private ProviderAccount providerAccount;
3.Here's the part in my actual controller which called the method 'predicate'.
List<AuxiliaryAccount> accounts = auxiliaryService.getAuxiliaryAccounts( account.getPerson() );
ProviderAccount provider = auxiliaryService.getProviderAccount( UserAccountUtil.getUserName() );
AuxiliaryAccount aux =
( AuxiliaryAccount ) CollectionUtils.find( accounts, PredicateUtils.notNullPredicate() );
Integer pid = provider.getId();
if ( CollectionUtils.find( aux.getProviderAuxiliaryAccounts(), predicate( pid ) ) != null )
Notice that the ProviderAuxiliaryAccount has a transient ProviderAccount property. Also,
I added a #Transactional anotation on my controller test class as stated here.
OpenEntityManagerInView equivalent for Junit and Quartz Jobs .
But this doesn't seem to work for me.
Does anyone know how to fix this?

Related

#Before not setting up data during integration test

I am creating an integraiton test for a JpaRepository and the testcase fails with "Record not found with random value rand", as null is returned in the find results.
My test case:
#SpringBootTest
class JpatestsApplicationTests {
#Autowired
private JpaRepo jpaRepo;
#Before
void setup() {
FirstTable firstTable1 = new FirstTable();
firstTable1.setUid("x");
firstTable1.setRandom("rand");
jpaRepo.save(firstTable1);
}
#Test
void testFindByRandom() {
FirstTable f = jpaRepo.findByRandom("rand");//find by random value 'rand'
Assert.notNull(f, "Record not found with random value rand ");
}
The entity associated:
#Entity
#Table(name = "table1")
public class FirstTable {
#Id
#GeneratedValue
private String uid;
#Column
private String random;
And my Repository:
#Repository
public interface JpaRepo extends JpaRepository<FirstTable, Long> {
FirstTable findByRandom(String rand);
}
I am using h2 database.
Why is the result coming as null for findByRandom? Also please note that if I move the record saving part jpaRepo.save(firstTable1) to be within the test case (before the findByRandom("rand") is called, it gets passed.
Why wouldn't it work if I save the record in setup() method annotated with #Before ?
You have to add #Transactional on the top of your class.
#Transactional will cause your tests to execute within a test-managed transaction that will be rolled back after the test completes; code executed within the #Before method will be executed inside the test-managed transaction.
The latest version of spring-boot-test makes use of junit 5 and #Before is deprecated. It started working after changing to #BeforeAll with annotation of #TestInstance(TestInstance.Lifecycle.PER_CLASS) at the class level
My updated test class:
#SpringBootTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
class JpatestsApplicationTests {
#Autowired
private JpaRepo jpaRepo;
#BeforeAll
void setup() {
FirstTable firstTable1 = new FirstTable();
firstTable1.setUid("x");
firstTable1.setRandom("rand");
jpaRepo.save(firstTable1);
}
#Test
void testFindByRandom() {
FirstTable f = jpaRepo.findByRandom("rand");//find by random value 'rand'
Assert.notNull(f, "Record not found with random value rand ");
}
Chose BeforeAll over BeforeEach as I need to run it only once during execution of this class.
Reference: https://junit.org/junit5/docs/current/user-guide/

#Accessors(fluent = true) from lombok and mapstruct together

I have a downstream service whose beans I want to map to my beans. But there seems to be a problem with using mapstruct.
Pojo from the downstream service (whose definition i can't change)
#ToString
#Getter
#Setter
#Accessors(fluent = true)
public class PojoA {
private String stringA;
private int integer;
}
and I want to convert it to PojoB
#Setter
#Getter
#ToString
public class PojoB {
private String stringB;
private int integer;
}
Mapper Interface
#Mapper
public interface PojoMapper {
PojoMapper INSTANCE = Mappers.getMapper(PojoMapper.class);
#Mapping(source = "stringA", target = "stringB")
PojoB pojoAToPojoB(PojoA pojoA);
}
This fails as it fails to find getters as fluent remove the prefixes from the getters and,
I know mapstruct generates the implementation of the mapper interface and uses bean specifications (i.e get and set prefixes)
Is there a way to get past that?
As specified in the comments this is possible by writing a custom AccessorNamingStrategy which would return the name of the method as a fluent accessor.
I have written a custom builder accessor (that can be applied in your case as well), you can find it here.
On top of that there is an open PR #1373 for MapStruct which adds support for builders and in the same go it adds support for fluent chained accessors.
Your custom strategy (as proposed in the PR) can look like:
public class FluentAccessorNamingStrategy extends DefaultAccessorNamingStrategy {
#Override
public boolean isSetterMethod(ExecutableElement method) {
String methodName = method.getSimpleName().toString();
return methodName.startsWith( "set" ) && methodName.length() > 3 || isBuilderSetter( method );
}
protected boolean isBuilderSetter(ExecutableElement method) {
return method.getParameters().size() == 1 &&
!JAVA_JAVAX_PACKAGE.matcher( method.getEnclosingElement().asType().toString() ).matches() &&
method.getReturnType().toString().equals( method.getEnclosingElement().asType().toString() );
}
#Override
public String getPropertyName(ExecutableElement getterOrSetterMethod) {
String methodName = getterOrSetterMethod.getSimpleName().toString();
if ( methodName.startsWith( "is" ) || methodName.startsWith( "get" ) || methodName.startsWith( "set" ) ) {
return Introspector.decapitalize( methodName.substring( methodName.startsWith( "is" ) ? 2 : 3 ) );
}
else if ( isBuilderSetter( getterOrSetterMethod ) ) {
return methodName;
}
return Introspector.decapitalize( methodName.substring( methodName.startsWith( "is" ) ? 2 : 3 ) );
}
}
NB: This would work for fluent setters, you would need to do something extra to make it work for the fluent getters. Based on the meethod.getEnclosingElement(), which returns you the type, you would need to get the Accessors annotation check for the property and return the name of the method, otherwise you need to use the defaults.
Disclaimer: I am one of the members of the MapStruct team

how to persist only the properties that were assigned in spring crudrepository?

I'm running in to a small problem with persisting an object. Here's an example of what my entity class looks like.
#Entity
public class Example(){
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private int number;
private String sentence;
/* No arg const, getters and setters omitted */
CrudRepository Interface:
#Repository
public interface ExampleRepository extends CrudRepository<Example, Integer>
{}
Service that implements the Interface:
#Service
public class ExampleService{
#Autowired
public ExampleRepository exampleRepository;
public void save(Example example){
exampleRespository.save(example)
}
}
Inside of CommandLineRunner:
Example example1 = new Example();
example1.sentence("Hello World!");
exampleService.save(example1);
Now the problem that I'm running into is that even though I didn't assign any value to the property number, it is still getting persisted as 0. How do I stop that property from getting assigned a value of 0 and make it null?
Change
private int number;
into
private Integer number;
the above solution is fine but again if you see in insert query for your save function, It insert all 3 column even you assigned only once column example1.sentence("Hello World!");
you can used #DynamicInsert(true) #DynamicUpdate(true) on Entity level,
this will fire query as
insert into example(sentence) values('Hello World!');
so query performance will increase

Lazy exception : size vs eager?

I was faced to a :
failed to lazily initialize a collection of role: ,no session or session was closed
When trying to access (from the controller, or a junit) the collection of "DataDictionaryEntry" that are in a "DataDictionary".
DataDictionary
#Entity
#Table( name = "IDS_RAVE_DATA_DICTIONARY",
uniqueConstraints={#UniqueConstraint(columnNames={"name"})
})
public class DataDictionary extends UnversionedObject {
#Column
private String name;
#OneToMany(mappedBy="dataDictionary",fetch=FetchType.EAGER)
private Collection<DataDictionaryEntry> dataDictionaryNames;
/* constructor */
public DataDictionary() {
super();
}
/* getters & setters */
}
DataDictionaryEntry
#Entity
#Table( name = "IDS_RAVE_DATA_DICTIONARY_ENTRY",
uniqueConstraints={#UniqueConstraint(columnNames={"dataDictionary","codedData"})
})
public class DataDictionaryEntry extends UnversionedObject {
#ManyToOne
#JoinColumn(name="dataDictionary")
private DataDictionary dataDictionary;
#Column
private String codedData;
#Column
private Integer ordinal;
#Column
private String userDataString;
#Column
private Boolean specify;
/* constructor */
public DataDictionaryEntry() {
super();
}
/* getters & setters */
}
I do have an abstract service object and another service extending it :
Generic service
#Transactional
public abstract class RaveGeneralServiceImpl<T> implements RaveGeneralService<T> {
private JpaRepository<T, Long> repo;
/**
* Init the general rave services with your specific repo
* #param repo
*/
protected void init(JpaRepository<T, Long> repo){
this.repo = repo;
}
#Override
public List<T> findAll(){
return repo.findAll();
}
#Override
public T save(T obj){
return repo.save(obj);
}
#Override
public void flush(){
repo.flush();
}
}
DataDictionaryServiceImpl
#Service
public class DataDictionaryServiceImpl extends RaveGeneralServiceImpl<DataDictionary> implements DataDictionaryService {
#Resource
private DataDictionaryRepository dataDictionaryRepository;
#PostConstruct
public void init() {
super.init(dataDictionaryRepository);
}
}
I could find replies on how to solve it. The first solution often seen is to change to LAZY to a EAGER. When I printed the generated query when accessing a FINDALL() method it shows the following :
Hibernate:
/* select
generatedAlias0
from
DataDictionary as generatedAlias0 */ select
datadictio0_.ID as ID81_,
datadictio0_.createdByUser as createdB2_81_,
datadictio0_.createdTime as createdT3_81_,
datadictio0_.lastUpdateTime as lastUpda4_81_,
datadictio0_.lastUpdateUser as lastUpda5_81_,
datadictio0_.VERSION as VERSION81_,
datadictio0_.name as name81_
from
IDS_RAVE_DATA_DICTIONARY datadictio0_
Hibernate:
/* load one-to-many com.bdls.ids.model.rave.DataDictionary.dataDictionaryNames */ select
datadictio0_.dataDictionary as dataDic11_81_1_,
datadictio0_.ID as ID1_,
datadictio0_.ID as ID82_0_,
datadictio0_.createdByUser as createdB2_82_0_,
datadictio0_.createdTime as createdT3_82_0_,
datadictio0_.lastUpdateTime as lastUpda4_82_0_,
datadictio0_.lastUpdateUser as lastUpda5_82_0_,
datadictio0_.VERSION as VERSION82_0_,
datadictio0_.codedData as codedData82_0_,
datadictio0_.dataDictionary as dataDic11_82_0_,
datadictio0_.ordinal as ordinal82_0_,
datadictio0_.specify as specify82_0_,
datadictio0_.userDataString as userDat10_82_0_
from
IDS_RAVE_DATA_DICTIONARY_ENTRY datadictio0_
where
datadictio0_.dataDictionary=?
The 2nd solution we often see is to make a call to the .size() of the component that is being lazily initialized. So indeed by changing my service to this :
#Service
public class DataDictionaryServiceImpl extends RaveGeneralServiceImpl<DataDictionary> implements DataDictionaryService {
#Resource
private DataDictionaryRepository dataDictionaryRepository;
#PostConstruct
public void init() {
super.init(dataDictionaryRepository);
}
#Override
public List<DataDictionary> findAll() {
List<DataDictionary> results = super.findAll();
for (DataDictionary dd : results) {
dd.getDataDictionaryNames().size();// init lazy
}
return results;
}
}
The lazy exception is also gone ! But the end result is the same query... So the what is the added value of keeping it LAZY if the end-query is the same ? Or did I do it wrong ?
Suppose that for the front-end you would have a data table that displays only basic information (the name for example), it would call the findAll() but still query the complete dependencies of that object ?
While the results with this method are pretty much exactly the same, the value of keeping it lazy is that if you don't need it fetched in other queries, you don't automatically have it eagerly fetched. Making the relationship eager applies to every method of accessing that entity, while calling size on a collection forces it to be fetched for that one occurrence.
There are other ways that might be more efficient, such as using a join fetch qualifier in the JPA query itself, allowing the provider to fetch the relationship using a single select.
You can either use: Hibernate.initialize() to initialize Lazy collections.
Or using spring to avoid LazyException use filer in your web.xml:
<filter>
<filter-name>hibernateFilterChain</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hibernateFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
But remember, using lazy fetching is bad idea if you are thinking about good application design and performance.

Guarantee unique number generation with spring data and hibernate

I'm developing a spring mvc webapp with spring data and hibernate.
I've an entity composed by a boolean field and by an Integer field.
At beginning the boolean field is false and Integer field is null.
When boolean field become true I need to assign to the Integer field a unique value equals to MAX(seq) +1
To do it, I write my service method in this way:
#Override
public synchronized Obj save(Obj entry) {
if (entry.getBool() && entry.getSeq() == null){
Integer seq = objRepository.getLastSeq();
if (seq == null){
seq = 1;
}
entry.setSeq(seq);
}
return entry.save(entry);
}
And in my Reposiroty:
#Query("select MAX(seq)+1 FROM Obj")
Integer getLastSeq();
I put synchronized keyword to service method in order to be sure that only a thread at a time can get an unique MAX+1 number.. but I'm not sure if it works in all situation and if it is the right way.
Can I be sure that it guarantee unicity of seq?
Thank you
Marco
It seems like your Integer is entry id or isn't it ? So why not to use database sequence, with #id adnotation for example :
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
Example how to use initializing bean for that purpose.
#Service
public class SequenceInitializer implements InitializingBean{
#Autowired
private ObjRepository objRepository;
#Autowired
private Service service;
#Override
public void afterPropertiesSet() throws Exception {
try {
Integer max = objRepository.getLastSeq();
service.setLastSeq(max);
} catch(Exception e){...}
}
In your service setLastSeq will set AtomicInteger field.

Resources