Lombok toBuilder Null Check - spring

I have a scenario where I am using Lombok #Builder annotation.Previously I was using static inner builder class but now with the use of Lombok I removed it.
But I am seeing fortify issue of null dereference in the following line of code.Also it makes sense as I am checking for null before but later when using toBuilder I am not checking null.How can I fix this fortify issue, should I do a null check for "requestCheck" again when using toBuilder.
requestCheck is a object of type Foo.
public Foo checkLatestMessage(Foo requestCheck){
if (requestCheck != null && requestCheck.isCheckLatestMessage()) { // null check
getLatestMessage(messages);
}
if (someOtherCondition) {
return requestCheck.toBuilder().addMessages(messages).build(); //Null dereference
}
}
Previously I had the code written in the following way when I was using static inner builder class and not Lombok which did not give any fortify issue.How can I achieve this same thing with Lombok Builder so that I don't have to do a null check.
return new Foo.Builder(requestCheck).addMessages(messages).build();

If it is possible for requestCheck to be a null, then it should be correctly handled.
public Foo checkLatestMessage(Foo requestCheck){
if (requestCheck != null) { // null check
if(requestCheck.isCheckLatestMessage()) {
getLatestMessage(messages);
}
if (someOtherCondition) {
return requestCheck.toBuilder().addMessages(messages).build();
}
}
}
Or you could return as soon as requestCheck is null.
public Foo checkLatestMessage(Foo requestCheck){
if (requestCheck == null) { // null check
return null;
}
if(requestCheck.isCheckLatestMessage()) {
getLatestMessage(messages);
}
if (someOtherCondition) {
return requestCheck.toBuilder().addMessages(messages).build();
}
}

Related

Spring Data JPA : Efficient Way to Invoke Repository Methods with Optional Parameters

I have the below Java 11 method which is invoked by the controller where ID is the required param and status,version are optional params. I had to write multiple repository methods to fetch the record based on those params. Am wondering is there a better/effiecient way to refactor this method with out the if/else ladder?
#Override
#Transactional(transactionManager = "customTransactionManager")
public Optional<String> getInformation(UUID id, Status status, Long version) {
try {
Preconditions.checkNotNull(id, ID_MUST_BE_NOT_NULL_MSG);
if (status != null && version != null) {
return repository.findByIdAndVersionAndStatus(id, version, status);
} else if (status != null) {
return repository.findFirstByIdAndStatus(id, status);
} else if (version != null) {
return repository.findFirstByIdAndVersion(id, version);
} else {
return repository.findFirstByIdOrderByIdDesc(id);
}
} catch (Exception e) {
log.error(e);
throw new CustomException(MessageFormat.format(PUBLIC_ERROR_MESSAGE, id));
}
}
You could use Specifications for that:
private Specification<YourEntity> toSpecification(UUID id, Status status, Long version) {
return (root, query, builder) -> {
Set<Predicate> predicates = new HashSet<>();
predicates.add(builder.equal(root.get("id"), id));
if (status != null) predicates.add(builder.equal(root.get("status"), status));
if (version != null) predicates.add(builder.equal(root.get("version"), version));
return builder.and(predicates.toArray(Predicate[]::new));
};
}
If you let your repository extend JpaSpecificationExecutor you can use the build specification object like so:
Specification<YourEntity> specification = toSpecification(id, status, version);
Optional<YourEntity> result = repository.findOne(specification);
When using Hibernate Metamodel Generator you can also write builder.equal(YourEntity_.id, id) instead of builder.equal(root.get("id"), id).
In addition to the accepted answer, I find Query By Examples much more intuitive and simple.
https://www.baeldung.com/spring-data-query-by-example would be a good start.
It basically creates a query based on non-null fields from your jpa entity.

Getting multiple Mono objects with reactive Mongo queries

I'm using the webflux framework for spring boot, the behavior I'm trying to implement is creating a new customer in the database, if it does not already exist (throw an exception if it does)
and also maintain another country code database (if the new customer is from a new country, add to the database, if the country is already saved, use the old information)
This is the function in the service :
public Mono<Customer> createNewCustomer(Customer customer) {
if(!customer.isValid()) {
return Mono.error(new BadRequestException("Bad email or birthdate format"));
}
Mono<Customer> customerFromDB = customerDB.findByEmail(customer.getEmail());
Mono<Country> countryFromDB = countryDB.findByCountryCode(customer.getCountryCode());
Mono<Customer> c = customerFromDB.zipWith(countryFromDB).doOnSuccess(new Consumer<Tuple2<Customer, Country>>() {
#Override
public void accept(Tuple2<Customer, Country> t) {
System.err.println("tuple " + t);
if(t == null) {
countryDB.save(new Country(customer.getCountryCode(), customer.getCountryName())).subscribe();
customerDB.save(customer).subscribe();
return;
}
Customer cus = t.getT1();
Country country = t.getT2();
if(cus != null) {
throw new CustomerAlreadyExistsException();
}
if(country == null) {
countryDB.save(new Country(customer.getCountryCode(), customer.getCountryName())).subscribe();
}
else {
customer.setCountryName(country.getCountryName());
}
customerDB.save(customer).subscribe();
}
}).thenReturn(customer);
return c;
}
My problem is, the tuple returns null if either country or customer are not found, while I need to know about them separately if they exist or not, so that I can save to the database correctly.
country == null is never true
I also tried to use customerFromDB.block() to get the actual value but I receive an error that it's not supported, so I guess that's not the way
Is there anyway to do two queries to get their values?
Solved it with the following solution:
public Mono<Customer> createNewCustomer(Customer customer) {
if(!customer.isValid()) {
return Mono.error(new BadRequestException("Bad email or birthdate format"));
}
return customerDB.findByEmail(customer.getEmail())
.defaultIfEmpty(new Customer("empty", "", "", "", "", ""))
.flatMap(cu -> {
if(!cu.getEmail().equals("empty")) {
return Mono.error(new CustomerAlreadyExistsException());
}
return countryDB.findByCountryCode(customer.getCountryCode())
.defaultIfEmpty(new Country(customer.getCountryCode(), customer.getCountryName()))
.flatMap(country -> {
customer.setCountryName(country.getCountryName());
customerDB.save(customer).subscribe();
countryDB.save(country).subscribe();
return Mono.just(customer);});
});
}
Instead of doing both queries simulatneaously, I queried for one result and then queries for the next, I think this is the reactive way of doing it, but I'm open for corrections.

is there a isnull or ifnull function in doctrine?

I am looking for a function in doctrine for converting null values to specified default values. So IsNull(A, B) should return B if A is null, A otherwice. Has doctrine such a function?
If you are talking about grabbing null values from an object, write a method in your entity
<?php
// Entities/SomeEntity.php
class Foo
{
private $a;
private $b;
// ...
// Your getters and setters are here
// ...
public function myNullFunction()
{
if($this->a === null AND $this->b !== null)
{
return $this->b;
}
elseif($this->b === null && $this->a !== null)
{
return $this->a;
}
else
{
// ... Do something if both are null
}
}
}
You can then use the function whenever you have loaded your object(s)
$foo = $some_repository->getFooObject();
// The function returning a value that is a or b
$bar = $foo->myNullFunction();
You can use the following project which contains some MSSQL functions for doctrine:
https://github.com/naprstek/doctrine-functions

How do I load an entity from a database where the Composite ID of the record contains a key-property with a null value?

I am reading data from an external organisation using Oracle.DataAccess through the Oracle10g provider. One of the tables has a composite id made up of these fields.
course:
institutioncode: "X11"
coursecode: "N100"
campuscode: "A"
entryyear: 2011
entrymonth: 10
The problem is that the campus code is allowed to be null by the external provider instead of empty. This leads to nHibernate returning collections that contain null references instead of course entities.
Other domain objects will use these fields to refer to this course entity as well, so this is actually used as a key and I can't easily remap to use a surrogate key.
From the source in tag 3.1.0GA, the check that is causing this behavior can be found in Nhibernate.Type.ComponentType.Hydrate(IDataReader rs, string[] names, ISessionImplementor session, object owner). This is always refusing the possibility that a key-property could be null. Could this change to make nullability an option on key-property and key-reference properties?
Failing that, how would you recommend reading this data directly with nHibernate?
NULL values in properties are not supported by design.
There are two ways to deal with this:
Import the data instead of using it raw from the source, adding a proper surrogate key.
Handle that entity without NHibernate.
ok my first comment didnt worked out on References (ManyToOne). So here my alternative solution: a usertype to work around the check.
class CourseMap : ClassMap<Course>
{
public CourseMap()
{
CompositeId()
.KeyProperty(c => c.InstitutionCode)
.KeyProperty(c => c.CourseCode)
.KeyProperty(c => c.CampusCode, key => key.Type(typeof(MyUserType)))
.KeyProperty(c => c.EntryYear)
.KeyProperty(c => c.EntryMonth);
}
}
class MyUserType : IUserType
{
public object Assemble(object cached, object owner)
{
return DeepCopy(cached);
}
public object DeepCopy(object value)
{
return value;
}
public object Disassemble(object value)
{
return DeepCopy(value);
}
public new bool Equals(object x, object y)
{
return object.Equals(x, y);
}
public int GetHashCode(object x)
{
return (x == null) ? 0 : x.GetHashCode();
}
public bool IsMutable
{
get { return false; }
}
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
var value = NHibernateUtil.String.NullSafeGet(rs, names[0]);
return (value == null) ? string.Empty : value;
}
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
string d = string.IsNullOrEmpty((string)value) ? null : (string)value;
NHibernateUtil.String.NullSafeSet(cmd, d, index);
}
public object Replace(object original, object target, object owner)
{
return DeepCopy(original);
}
public Type ReturnedType
{
get { return typeof(string); }
}
public SqlType[] SqlTypes
{
get { return new[] { SqlTypeFactory.GetString(100) }; }
}
}
class SomeEntityMap : ClassMap<SomeEntity>
{
public EntityMap()
{
Id(e => e.Id).GeneratedBy.Assigned();
References(e => e.Course)
.Columns("InstitutionCode", "CourseCode", "CampusCode", "EntryYear", "EntryMonth")
.Fetch.Join(); // important because we can't rely on values, NULL is invalid value
}
}

Saving a custom object using IsloatedStorageSettings

I'm trying to save an object in IsolatedStorageSettings to save the high scores for my game, but whenever I try to save an updated copy of the object C# seems to think the object hasn't changed. I tried creating a custom Equals function for the HighScores class but that doesn't seem to help.
Any idea what I'm doing wrong?
Thanks
public bool AddOrUpdateValue(string Key, Object value)
{
bool valueChanged = false;
// If the key exists
if (isolatedStore.Contains(Key))
{
// If the value has changed
if (isolatedStore[Key] != value) //This keeps returning false
{
// Store the new value
isolatedStore[Key] = value;
valueChanged = true;
}
}
// Otherwise create the key.
else
{
isolatedStore.Add(Key, value);
valueChanged = true;
}
return valueChanged;
}
//This is located inside the HighScores class
public bool Equals(HighScores newHighScores)
{
for (int i = 0; i < highScores.Length; i++)
{
if (!highScores[i].Name.Equals(newHighScores.GetIndex(i).Name))
{
return false;
}
if (!highScores[i].Time.Equals(newHighScores.GetIndex(i).Time))
{
return false;
}
}
return true;
}
You haven't implemented the equality operators '==' and '!=' and these compare reference equality, you are going to have provide the implementation which maps on to your 'Equals' method
http://msdn.microsoft.com/en-us/library/ms173147%28v=vs.80%29.aspx
You should do isolatedStore.Save() to commit the changes

Resources