Initialize JPA-like entities with JDBC - java

I'm implementing several DAO classes for a web project and for some reasons I have to use JDBC.
Now I'd like to return an entity like this:
public class Customer{
// instead of int userId
private User user;
// instead of int activityId
private Activity act;
// ...
}
Using JPA user and activity would be loaded easily (and automatically specifying relations between entities).
But how, using JDBC? Is there a common way to achieve this? Should I load everiting in my CustomerDAO? IS it possible to implement lazy initialization for referenced entities?
My first idea was to implement in my UserDAO:
public void initUser(Customer customer);
and in my ActivityDAO:
public void initActivity(Customer customer);
to initialize variables in customer.

Active Record route
You could do this with AspectJ ITDs and essentially make your entities into Active Record like objects.
Basically you make an Aspect that advises class that implement an interface called "HasUser" and "HasActivity". Your interfaces HasUser and HasActivity will just define getters.
You will then make Aspects that will weave in the actual implementation of getUser() and getActivity().
Your aspects will do the actual JDBC work. Although the learning curve on AspectJ is initially steep it will make your code far more elegant.
You can take a look at one of my answers on AspectJ ITD stackoverflow post.
You should also check out springs #Configurable which will autowire in your dependencies (such as your datasource or jdbc template) into non managed spring bean.
Of course the best example of to see this in action is Spring Roo. Just look at the AspectJ files it generates to get an idea (granted that roo uses JPA) of how you would use #Configurable (make sure to use the activerecord annotation).
DAO Route
If you really want to go the DAO route than you need to this:
public class Customer{
// instead of int userId
private Integer userId;
// instead of int activityId
private Integer activityId;
}
Because in the DAO pattern your entity objects are not supposed to have behavior. Your Services and/or DAO's will have to make transfer objects or which you could attach the lazy loading.

I'm not sure if there is any automated approach about this. Without ORM I usually define getters as singletons where my reference types are initialized to null by default, i.e. my fetching function would load primitives + Strings and will leave them as null. Once I need getUser(), my getter would see if this is null and if so, it would issue another select statement based on the ID of the customer.

Related

How to extend non-modifiable model to use with JPA?

What's the best practice to create persistence (say via Spring Boot or just JPA or Hibernate itself) for a data model coming from a non-modifiable dependency? Typical limitations like not being able to override a field or what patterns like Decorator allow and what not slowed my progress down. I tried some things, but I always end up with the result that it would be necessary to either modify the source model (like adding annotations to make it natively compatible -> the fork I don't want) OR write a ton of wrapper code which would replicate the original model too much - but even this isn't working right now:
I tried
Creating a JpaRepository for the original class. Doesn't work, because casting the extended class to its parent class is not working.
Extend the original class with a custom class that gets necessary annotations like #Entity can be used in such a repository. But problems here were
that the original class is missing an #Id annotation, which could be fixed by using a new ID in the extended class, but
the given model also has a non-simple architecture, including lists of other classes that are part of the model itself. So other annotations like #ElementCollection might be necessary, which can't be added because overriding of fields is not possible.
Hiding it with creating a new field with the same name in the new class is not working:
An error like Could not determine type for: java.util.List, at table: yeah_this_one, for columns:[org.hibernate.mapping.Column(objects)] indicates that the original field can't be hidden completely (changed table and column name in new class to verify that).
So of course adding #ElementCollection (which is said to solve that) isn't helping here, too.
#AttributeOverride is also not working to override annotations to set the ID or other settings, only the name and column can be changed.
I'm stuck at this state and am wondering if this is even the right approach at all.
The setup or what I would expect to work from my understanding:
The general idea is based on this Spring Boot REST tutorial, which I tried to expand with a model from a dependency.
Let's assume there is the original model class Model from a dependency that can not be modified. The ModelEntity would be the extended class to act as way to pull the model into Spring persistence.
In the scope of the dependency the original class would be like:
// Given dependency, not modifiable
#Some existing annotation
public class Model extends AnotherClassFromDep {
#more annotations
private IdLikeClassFromDep modelId;
//more complex attribute
#Nullable
private List<RefClassFromDep> objects = new ArrayList<>();
// more attributes, getter, setter etc.
}
In the scope of my program:
In combination with this little additional orm.xml it is possible to annotate the original Model as MappedSuperclass without modifying it (according to https://stackoverflow.com/a/2516951/1844976).
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">
<mapped-superclass class="package.name.of.original.Model">
</mapped-superclass>
</entity-mappings>
This allows to create a class like this, which extends the original POJO model to add JPA annotations:
#Entity
public class ModelEntity extends Model {
// some #Id attribute is necessary, which should correspond to
// the already existing ID attribute from the original `Model`
// in the best case, but an additional one would work too
private #Id #GeneratedValue Long id;
// Different approaches to solve the List error from above, for
// instance hiding the original attribute
#ElementCollection
private List<RefClassFromDep> objects;
public ModelEntity(){
super();
}
}
At the current state the issues are blocking me from going further. But, altogether I would expect this to work with a JpaRepository:
// of course, creating a JpaRepository with original `Model` wouldn't
// work, because it has no `#Entity`
public interface ModelRepository extends JpaRepository<ModelEntity, IdLikeClassFromDep> {
}
In a way that actually accessing it like that is possible:
#Configuration
public class LoadDatabase {
#Bean
CommandLineRunner initDatabase(ModelRepository modelRepository) {
return args -> {
// depending on the implementation above, either create a
// Model and cast it or directly create a ModelEntity, set
// attriubtes and save it through the JpaRepository
modelRepository.save(model);
};
}
}
Both more abstract and specific code-related ideas and comments would help me. Thanks!
In the old days, Jpa/Hibernate were configured via XML.
You needed to provide persistence.xml for general configuration. In this file, you added <mapping-file> tag pointing to another file orm.xml In this file you configured mapping for your entities (which is done via JPA annotations these days).
See https://vladmihalcea.com/how-to-use-external-xml-mappings-files-outside-of-jar-with-jpa-and-hibernate/
While the methods described above are considered legacy, they are still supported. LocalContainerEntityManagerFactoryBean has method setMappingResources allowing you to point to the orm.xml file. There is some funkiness about search paths and default locations, but it is well documented:
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.html#setMappingResources-java.lang.String...-
Note that the third-party class you are configuring this way needs to conform to Java Beans conventions (no-args constructor, getters and setters)

#Transactional annotation Spring boot 2.0 and hibernate LazyInitializationException

I have the following question. From what I understand the #Transactional annotation is supposed to keep the session alive, thus enabling to lazy fetch child entities without the need to performe a specific joining query.
I have the following scenario where I do not understand why I'm still getting a LazyInitializationException.
My app runs a resolver in order to provide the various controller services with a resolved object so that it can be used directly.
Said resolver intercepts a header from the request and using it's value attempts to query the db in order to fetch the object. Now the object in question is quite simple is it's doings albeit it has a list of two sub-entities.
In order to perform the resolving action I'm using an extra service where I basically wrap some JpaRepository methods. The complete is below:
#Service
public class AppClientServiceImpl implements AppClientService {
private static final Logger LOGGER = LoggerFactory.getLogger(AppClientServiceImpl.class.getCanonicalName());
private final AppClientRepository repository;
#Autowired
public AppClientServiceImpl(AppClientRepository repository) {
this.repository = repository;
}
#Override
#Transactional(readOnly = true)
public AppClient getByAppClientId(final String appClientId) {
LOGGER.debug("Attempting to retrieve appClient with id:: {}", appClientId);
return repository.findByAppClientId(appClientId);
}
#Override
#Transactional
public void saveAndFlush(final AppClient appClient) {
LOGGER.debug("Attempting to save/update appClient:: {}", appClient);
repository.saveAndFlush(appClient);
}
}
As you can see both methods are annotated as #Transactional meaning that the should keep the session alive in the context of that said method.
Now, my main questions are the following:
1) Using the debugger I'm seeing even on that level getByAppClientId the list containing on the sub-entities which is lazy loaded has been resolved just fine.
2) On the resolver itself, where the object has been received from the delegating method, the list fails to be evaluated due to a LazyInitializationException.
3) Finally on the final controller service method which is also marked as #Transactional, the same as above occurs meaning that this eventually fails to it's job (since it's performing a get of the list that has failed to initialize.
Based on all the above, I would like to know what is the best approach in handling this. For once I do not want to use an Eager fetching type and I would also like to avoid using fetch queries. Also marking my resolver as #Transactional thus keeping the session open there as well is also out of the question.
I though that since the #Transactional would keep the session open, thus enabling the final service method to obtain the list of sub-entities. This seems not to be the case.
Based on all the above it seems that I need a way for the final service method that gets call (which needs the list on hand) to fetch it somehow.
What would the best approach to handle this? I've read quite a few posts here, but I cannot make out which is the most accepted methods as of Spring boot 2.0 and hibernate 5.
Update:
Seems that annotating the sub-entitie with the following:
#Fetch(FetchMode.SELECT)
#LazyCollection(LazyCollectionOption.TRUE)
Resolves the problem but I still don't know whether this is the best approach.
You initialize the collection by debugging. The debugger usually represents collections in a special way by using the collection methods which trigger the initialization, so that might be the reason why it seems to work fine during debugging. I suppose the resolver runs outside of the scope of the getByAppClientId? At that point the session is closed which is why you see the exception.
I created Blaze-Persistence Entity Views for exactly that use case. You essentially define DTOs for JPA entities as interfaces and apply them on a query. It supports mapping nested DTOs, collection etc., essentially everything you'd expect and on top of that, it will improve your query performance as it will generate queries fetching just the data that you actually require for the DTOs.
The entity views for your example could look like this
#EntityView(AppClient.class)
interface AppClientDto {
String getName();
}
Querying could look like this
List<AppClientDto> dtos = entityViewManager.applySetting(
EntityViewSetting.create(AppClientDto.class),
criteriaBuilderFactory.create(em, AppClient.class)
).getResultList();

Extend spring data's default syntax

In my current project almost every entity has a field recordStatus which can have 2 values:
A for Active
D for Deleted
In spring data one can normally use:
repository.findByLastName(lastName)
but with the current data model we have to remember about the active part in every repository call, eg.
repository.findByLastNameAndRecordStatus(lastName, A)
The question is: is there any way to extend spring data in such a way it would be able to recognize the following method:
repository.findActiveByLastName(lastName)
and append the
recordStatus = 'A'
automatically?
Spring Data JPA provides 2 additional options for you dealing with circumstances that their DSL can't handle by default.
The first solution is custom queries with an #Query annotation
#Query("select s from MyTable s where s.recordStatus like 'A%'")
public MyObect findActiveByLastName(String lastName);
The second solution is to add a completely custom method the "Old Fashion Way" You can create a new class setup like: MyRepositoryImpl The Impl is important as it is How spring knows to find your new method (Note: you can avoid this, but you will have to manually link things the docs can help you with that)
//Implementation
public class MyRepositoryImpl implements MyCustomMethodInterface {
#PersistenceContext
EntityManager em;
public Object myCustomJPAMethod() {
//TODO custom JPA work similar to this
String myQuery = "TODO";
return em.createQuery(myQuery).execute();
}
}
//Interface
public interface MyCustomMethodInterface {
public Object myCustomJPAMethod();
}
//For clarity update your JPA repository as well so people see your custom work
public interface MySuperEpicRepository extends JPARepository<Object, String>, MyCustomMethodInterface {
}
These are just some quick samples so feel free to go read their Spring Data JPA docs if you would like to get a bit more custom with it.
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/
Finally just a quick note. Technically this isn't a built in feature from Spring Data JPA, but you can also use Predicates. I will link you to a blog on this one since I am not overly familiar on this approach.
https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
You can use Spring Data's Specifications. Take a look at this article.
If you create a 'Base'-specification with the recordStatus filter, and deriving all other specifications form this one.
Of course, everybody in your team should use the specifactions api, and not the default spring data api.
I am not sure you can extend the syntax unless you override the base class (SimpleReactiveMongoRepository; this is for reactive mongo but you can find the class for your DB type), what I can suggest you is to extend the base methods and then make your method be aware of what condition you want to execute. If you check this post you get the idea that I did for the patch operation for all entities.
https://medium.com/#ghahremani/extending-default-spring-data-repository-methods-patch-example-a23c07c35bf9

How to instantiate a class from string FQN in database in hibernate?

I'm trying to convert a legacy application to hibernate.
I have an entity that has a field, which should be instantiated to object instance based on a fully qualified name string in a database.
Consider the example below - if I have somePackageName.FirstClass in a database the someObject field should be an instance of FirstClass.
I guess I could use property access and persist / retrieve a string but that doesn't look very elegant to me.
I cannot use #PostLoad etc. - I'm using pure hibernate with spring (not JPA) - these annotations get ignored.
I know for example in MyBatis one can register a custom handler for field. Would anything similar be available in Hibernate?
I'm new to hibernate so I'm not really sure what the options are.
#Entity
class SomePersistentClass{
private SomeInterface someObject;
}
class FirstClass implements SomeInterface{
}
class SecondClass implements SomeInterface{
}
You can use JPA features such as #PostLoad, etc callbacks simply by enabling the proper Hibernate event listeners. Check the Hibernate EntityManager guide for details.
But this one is even easier. This is the role of a Type in Hibernate. First, you'll have to write an implementation of org.hibernate.type.Type or org.hibernate.usertype.UserType and specify that in #Type( type=... ) that handles the conversions (lots of web resources about writing custom Hibernate types). Then annotate your 'someObject' attribute with #Type( type="your.custom.TypeImpl" )

How to access Session information on service layer?

Is there a way I can share Http/Wicket Session information to the service layer without introducing servlet api/Wicket dependency?
I'll provide some context to why am I asking this question, just in case I'm missing something and asking the wrong question.
I've got several entities that have groups of attributes that can be validatable.
Being validatable means there are fields indicating the validation value, the user who made the validation and the date it was validated in.
This is how these entities are modelled:
#Embeddable
public class ValidationBean<T> implements Serializable {
private T validated;
private String user;
private Date date;
// Constructors, getters, setters ahead.
// ...
}
#Entity
#Table(name="SOME_TABLE")
public class SomeEntity implements Serializable, SomeInterface {
// Some attributes which conform validation group 1
public String attribute11;
public String attribute12;
public String attribute13;
private ValidationBean<Integer> validationBean1 = new ValidationBean<Integer>();
// Some attributes which conform validation group 2
public String attribute21;
private ValidationBean<String> validationBean2 = new ValidationBean<Integer>();
// Constructors, various attribute getters with JPA annotations
// ...
#Embedded
#AttributeOverrides(/*various overrides, each entity/validation group has its own validation column names...*/)
public ValidationBean<Integer> getValidationBean1() { return validationBean1; }
#Embedded
#AttributeOverrides(/*various overrides, each entity/validation group has its own validation column names...*/)
public ValidationBean<Integer> getValidationBean2() { return validationBean2; }
}
ValidationBean's user and date fields are automatically modified in the presentation layer when a change in the validated field is detected.
All of this is working correctly. Now, I'm trying to find an elegant & general solution that integrates with the current modelling to the following requirement: When any of the attributes in a validation group gets its value changed, and the related ValidationBean.validated doesn't change, user and date must also be modified with the current user's id and the current date.
There are, as I see it, two alternatives; putting that logic in the presentation layer, or in business/service layer
Putting it in the presentation layer would have an efficieny advantage. Entities are stored in session so that the DB doesn't have to be queried again to check for field changes. But unfortunately, some entities have some of their fields ajax-updated and it would be hard to tell if the entity really changed. Apart from not being the presentation layer's responsability to fulfill this requirement.
Putting it in the service layer seems the best alternative, and I've already found a possible way to handle this properly. I've come up with #PreUpdate. It would be easy to implement a #PreUpdate method on the #Entities to compare the values in DB with the values about to be updated, and modify the related ValidationBeans accordingly. The problem here, and I suppose it's a common problem, is that in the business layer, I don't have where to get the user id from. The current user Id is stored in the Session, which belongs to the presentation layer.
So, any tips, comments, recommendations on how can I share http session information to the service layer (not necessarily Wicket-specific), or even alternatives to fulfill this requirement will be welcome.
UDPATE : Following gkamal's suggestion, I'll try to integrate spring-security in the less intrusive way I can, just to take advantage of SecurityContext. I'd also appreciate tips on this matter.
The common approach used to solve this is to introduce a SecurityContext class that holds the details of the current user as a static thread local variable. The variable is initialized (from the httpsession) by the security filter or some other filter and cleared after the request processing is complete. The SecurityContext class will itself be part of the business layer which provides a set / get methods and hence doesn't have any web layer dependency.

Categories

Resources