I am having a service that gets the data from the database which has a column which is stored with encrypted value.
After fetching from the DAO, i will update the value of the property to decrypted value and then send it as response for the API.
I assume that the entity is having change tracking enabled for select queries also because after i get the data, the data is updated in the DB with the decrypted password. I have googled and found that the use of EntityManager solves the problem, but for this implementation I have to do a lot of code changes in many entities.
from this link, i see that we have to write custom stateless bean and inject to the code, but it looks like not right. Please suggest me the best approach to handle this problem.
My DAO:
#Repository
public interface EnvironmentDao extends JpaRepository<Environment, Long> {
//custom methods go here with native queries
}
My Service
#Override
public List<Environment> getEnvironmentsByIds(List<Long> environmentIds) throws Exception {
if (environmentIds == null || environmentIds.size() < 1) {
return null;
}
return decryptPassword(environmentDao.findAllById(environmentIds));
}
Inside the decryptPassword method, i am just looping through all the records and then setting the decrypted password like
e.setDB_Password(encryptionService.decrypt(e.getDB_Password()));
One case that i noticed yesterday is that for a similar entity on any error, there was a DB save and that time the values got updated, so after fixing the error, this change was not happening.
Please help me as I am not an expert in java and taking more time to analyze and could not understand. In the case of C#, i would use .AsNoTracking(), but i don't know java much and fiddling around.
Tried the following in the Service
#Autowired
EntityManager entityManager;
In the method,
Optional<Environment> environment = environmentDao.findById(id);
entityManager.detach(environment.get());
return managePassword(environment.get(), false);
I would suggest two options to overcome the entity being updated unintentionally:
Instead of returning the entity itself I would suggest creating a DTO class and creating an instance of that class and setting relevant properties on to the DTO instance so that no changes will be made to the entity itself. So the code will be sth like:
public List<EnvironmentDTO> getEnvironmentsByIds(List<Long> environmentIds) throws Exception {
if (environmentIds == null || environmentIds.size() < 1) {
return null;
}
return createEnvironmentDTOs(environmentDao.findAllById(environmentIds));
}
private LisT<EnvironmentDTO> createEnvironmentDTOs(List<Environment> environments) {
return environments.stream().map((env) -> {
EnvironmentDTO envDto = new EnvironmentDTO();
// Copy all relevant fields to DTO (you can even use some Mapper library for this, i.e. http://modelmapper.org/)
envDto.setDB_Password(encryptionService.decrypt(e.getDB_Password()));
})
}
If you want to return the entity no matter what instead of creating a DTO class and instance from it; you can detach the entity so that changes to the entity will not be reflected to database. So what you need to do is detaching entity after you are done with decrypting the password and setting it back to the entity: entityManager.detach(environment)
So i have a problem, I need to know ID of an object that is going to be used in database, before i Persist it.
What I need to do is create custom generator :
public class CustomEntityIdGenerator extends SequenceStyleGenerator {
#Override
public Serializable generate(SharedSessionContractImplementor session,
Object object) throws HibernateException {
if (object instanceof IWorkaround) {
IWorkaround workaround = (IWorkaround) object;
//TODO Generate UID from multiple Workaround properties.
return 1l;
} else {
throw new HibernateException("Cannot generate custom ID for this Entity, Must be IWorkaround");
}
}
}
Issue is : How do i safely and reliably Generate LONG ID from OBJECT PROPERTIES? I was thinking about concatenation of some of its properties into String, then do Hash of that string and somehow Put that HASH TO LONG, Problem is that HASH TO LONG part, how do i do this reliably? What kind of algorithm fits here?
Or is there a better way?
Note: Before someone asks, i cannot use +1 from sequence. Since This system can be used in parallel by multiple users. Cant rely on next number in sequence for id.
To better illustrate what im doing :
//Multiple people call
saveMe(objectToBePersisted){
createDirectoriesAndProcessResources(idThatWillBeUsedInDB)// <-- Now I use ID
otherStuff(objectToBePersisted);
//Might have been declined and method ends
saveToDB(objectToBePersisted)// <--now it gets ID
}
I'd recommend a simplified base 64 or 62 with random sequence, you can calculate the collision chances for a given length and base. You don't have to generate it from the properties. You can play around: https://alex7kom.github.io/nano-nanoid-cc
I use a custom access layer (not relational, not standardized in any way) which is in the form of a jar file, like an API. This access layer provides a custom way to filter the results when I ask a
"query". I wrap this custom data access layer using the Repository design pattern, following a design similar to the one described here, in order to hide its complexity to the above layers.
Therefore, one of my repository's functions to execute queries would be something like the one following:
public class Repository {
// Other methods...
public Set<CustomEntity> get(Predicate<CustomEntity> predicate) {
// code using the predicate in order to create a custom filter string
String filterExpression = ...;
Set<CustomEntity> queryResults = CustomDataAccessLayer.query(filterExpression);
return queryResults;
}
// Other methods...
}
A typical call of the above method would be something like
Set<CustomEntity> queryResults = customEntitiesRepository.get(
p -> p.property1 == "criterio 1" && p.property2 == "criterio 2"
);
Obviously, the method get would translate the predicate with two criteria in the custom access layer's filtering mechanism. However, I don't know how to retrieve the content of the predicate in order to apply the filters to the custom access layer. Is there such a mechanism? Is it feasible to use reflection API or something like that in order to retrieve a predicate's conditions?
Edit: I could retrieve all the entities from the custom access layer API and then check if they validate the predicate criteria through the Predicate.test
method. However, this would require retrieving all data
from the custom access layer in prior (eager loading), which is exactly what I am trying to avoid. I am trying to convert the predicate into a custom access layer filter string (namely the string variable filterExpression) in order to build a "lazy loading" repository.
I'm playing around with the ZK 8 MVVM form validation system and generally it seems to do what I want, but I wonder what the definition of the dependent property index is...
Let's take a simple validator...
public class FormValidator extends AbstractValidator {
#Override
public void validate(final ValidationContext ctx) {
Property[] properties = ctx.getProperties("firstName");
Object value0 = properties[0].getValue();
Object value1 = properties[1].getValue();
}
}
So, when this is called before the save command, for every property, I get a Property[] array of length 2. But somehow, I have yet to find out what is stored in [0] and what is stored in [1]. Sometimes it seems that [0] stores the current value (which may or may not be valid according the field validator there) and [1] the last valid entry... But sometimes it seems to be the other way round...
The examples in the documentation always seem to simply take the first element ([0]) for validation, but I would like the understand what both parts of this pair actually mean...
Anyone got an idea for that?
I might be off the mark with my answer, but if you are using ZK8, you should look into using Form binding
That way you do not have to handle Properties in your validator and can retrieve a proxy object matching the bean you use for your form.
If you are using a User POJO with a firstName and lastName attribut.
User myProxy= (User ) ctx.getProperty().getValue();
And then you can validate both fields by simply doing getFirstName and getLastName on myProxy.
Hope it helps.
From the spring documentation :
#Cacheable(value="bookCache", key="isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
How can I specify #Cachable to use isbn and checkWarehouse as key?
Update: Current Spring cache implementation uses all method parameters as the cache key if not specified otherwise. If you want to use selected keys, refer to Arjan's answer which uses SpEL list {#isbn, #includeUsed} which is the simplest way to create unique keys.
From Spring Documentation
The default key generation strategy changed with the release of Spring
4.0. Earlier versions of Spring used a key generation strategy that, for multiple key parameters, only considered the hashCode() of
parameters and not equals(); this could cause unexpected key
collisions (see SPR-10237 for background). The new
'SimpleKeyGenerator' uses a compound key for such scenarios.
Before Spring 4.0
I suggest you to concat the values of the parameters in Spel expression with something like key="#checkWarehouse.toString() + #isbn.toString()"), I believe this should work as org.springframework.cache.interceptor.ExpressionEvaluator returns Object, which is later used as the key so you don't have to provide an int in your SPEL expression.
As for the hash code with a high collision probability - you can't use it as the key.
Someone in this thread has suggested to use T(java.util.Objects).hash(#p0,#p1, #p2) but it WILL NOT WORK and this approach is easy to break, for example I've used the data from SPR-9377 :
System.out.println( Objects.hash("someisbn", new Integer(109), new Integer(434)));
System.out.println( Objects.hash("someisbn", new Integer(110), new Integer(403)));
Both lines print -636517714 on my environment.
P.S. Actually in the reference documentation we have
#Cacheable(value="books", key="T(someType).hash(#isbn)")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
I think that this example is WRONG and misleading and should be removed from the documentation, as the keys should be unique.
P.P.S. also see https://jira.springsource.org/browse/SPR-9036 for some interesting ideas regarding the default key generation.
I'd like to add for the sake of correctness and as an entertaining mathematical/computer science fact that unlike built-in hash, using a secure cryptographic hash function like MD5 or SHA256, due to the properties of such function IS absolutely possible for this task, but to compute it every time may be too expensive, checkout for example Dan Boneh cryptography course to learn more.
After some limited testing with Spring 3.2, it seems one can use a SpEL list: {..., ..., ...}. This can also include null values. Spring passes the list as the key to the actual cache implementation. When using Ehcache, such will at some point invoke List#hashCode(), which takes all its items into account. (I am not sure if Ehcache only relies on the hash code.)
I use this for a shared cache, in which I include the method name in the key as well, which the Spring default key generator does not include. This way I can easily wipe the (single) cache, without (too much...) risking matching keys for different methods. Like:
#Cacheable(value="bookCache",
key="{ #root.methodName, #isbn?.id, #checkWarehouse }")
public Book findBook(ISBN isbn, boolean checkWarehouse)
...
#Cacheable(value="bookCache",
key="{ #root.methodName, #asin, #checkWarehouse }")
public Book findBookByAmazonId(String asin, boolean checkWarehouse)
...
Of course, if many methods need this and you're always using all parameters for your key, then one can also define a custom key generator that includes the class and method name:
<cache:annotation-driven mode="..." key-generator="cacheKeyGenerator" />
<bean id="cacheKeyGenerator" class="net.example.cache.CacheKeyGenerator" />
...with:
public class CacheKeyGenerator
implements org.springframework.cache.interceptor.KeyGenerator {
#Override
public Object generate(final Object target, final Method method,
final Object... params) {
final List<Object> key = new ArrayList<>();
key.add(method.getDeclaringClass().getName());
key.add(method.getName());
for (final Object o : params) {
key.add(o);
}
return key;
}
}
You can use a Spring-EL expression, for eg on JDK 1.7:
#Cacheable(value="bookCache", key="T(java.util.Objects).hash(#p0,#p1, #p2)")
You can use Spring SimpleKey class
#Cacheable(value = "bookCache", key = "new org.springframework.cache.interceptor.SimpleKey(#isbn, #checkWarehouse)")
This will work
#Cacheable(value="bookCache", key="#checkwarehouse.toString().append(#isbn.toString())")
Use this
#Cacheable(value="bookCache", key="#isbn + '_' + #checkWarehouse + '_' + #includeUsed")