I am using Spring Boot 1.3.1 including Spring Data JPA. I'd like to execute a method after any lazy loading to do some translations on the loaded object.
Example:
#Entity
#Table(name = "commune")
public class Commune extends CommuneBase {
}
#MappedSuperclass
public abstract class CommuneBase {
private Region region;
}
#Entity
#Table(name = "region")
public class Region extends RegionBase {
}
#MappedSuperclass
public abstract class RegionBase {
private String name;
}
Testcode:
Commune commune = communeRepository.findOne(communeId);
Region region = commune.getRegion();
The result of getRegion() should now be translated.
I tried it with an aspect and the following pointcut:
#AfterReturning(pointcut="execution(* com.mycompany.application.data.domain.Commune.getRegion(..))", returning="returnValue")
The pointcut is not called. Other pointcuts in the same project are working as expected.
Any help is appreciated
Related
I am currently learning Spring for GraphQL and am working on an application to do some basic CRUD operations, using the GraphQL API using Spring-boot with JPA and an H2 in-memory database for testing. Now I am trying to write some integration tests using the GraphlQlTester interface. There is a possibility to test importing just the service layer, storing the data in a collection at this layer. Now I want to be able to access the repository layer too to temporarily store and manipulate the test data in the h2 database. I have been researching the documentation online, but unfortunately, I have not found any possible way to approach this particular issue. Perhaps you may have an idea?
Entity Class
#Data
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Table(name = "address")
public class Address {
#Id
#GeneratedValue(strategy = IDENTITY)
private long id;
private String street;
private String city;
private int postCode;
}
Controller Class (just the first method)
#Controller
#RequiredArgsConstructor
public class AddressController {
private final AddressService addressService;
private static final String ERROR_MESSAGE = "Address with id %d not found";
#QueryMapping
List<Address> findAllAddresses() {
return addressService.findAll();
}
Service Class (just the first method)
#Service
#RequiredArgsConstructor
public class AddressService {
private final String ERROR_MESSAGE = "Address with id %d not found";
private final AddressRepository addressRepository;
private final ContactInformationRepository contactInformationRepository;
public List<Address> findAll() {
return addressRepository.findAll();
}
Repository
public interface AddressRepository extends JpaRepository<Address, Long> {
}
Integration Test class
import com.soscarlos.dropit.entity.Address;
import com.soscarlos.dropit.repository.AddressRepository;
import com.soscarlos.dropit.service.AddressService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.graphql.GraphQlTest;
import org.springframework.context.annotation.Import;
import org.springframework.graphql.test.tester.GraphQlTester;
#GraphQlTest(AddressController.class)
#Import({AddressService.class, AddressRepository.class})
class AddressControllerTest {
#Autowired
GraphQlTester tester;
#Autowired
AddressService addressService;
#Autowired
AddressRepository addressRepository;
#Test
void findAllAddresses() {
// language=GraphQL
String document = """
query {
findAllAddresses {
id
street
city
postCode
}
}
""";
tester.document(document)
.execute()
.path("findAllAddresses")
.entityList(Address.class)
.hasSize(1);
}
I cannot load the application context because of this error basically
"Error creating bean with name 'com.soscarlos.dropit.repository.AddressRepository': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.soscarlos.dropit.repository.AddressRepository]: Specified class is an interface"
Need your help here in a Spring Data CrudRepository on how to do a findby of nested fields.
My class is of following structure and I need to query using truckId which is of the nested objects
#Document(collection = "unt-truck")
public class TruckModelDTO {
private String type;
private TestDTO testDTO;
}
Class TestDTO.java
public class TestDTO{
private TruckDTO truckDTO;
Private String version;
}
Class TruckDTO.java
public class TruckDTO {
private String truckId;
private String legacySystem;
}
Class TruckRepository.java
#Repository
public interface TruckRepository extends MongoRepository<TruckModelDTO, String> {
// TruckModelDTO findByTruckId(String truckid);
}
So how should I use findby for truckId which is inside a nested class?
You can use with either Entity or DTO as response. but you have to mention the relation between two or three Entity based on you requirement.
I have created Entity. you have to create DTO with same based on entity then apply main DTO as return type in JPA Repository query.
1.Entity
#Entity
public class TruckModel {
private String type;
// mention the relation based on your requirement
private Test test;
}
Entity
#Entity
public class Test {
// here mention the relation based on you requirement
private Truck truck;
Private String version;
}
3.Entity
#Entity
public class Truck {
private String truckId;
private String legacySystem;
}
Repository
#Repository
public interface TruckModelRepository extends MongoRepository<TruckModel, String> {
TruckModelDTO findByTestTruckTruckId(String truckid);
}
so I have following hierarchy of entities:
#MappedSuperClass
public abstract class BaseEntity {
private Long id;
private Date createAt;
private Date updateAt;
}
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Post extends BaseEntity {
private String creatorId;
private String title;
private String content;
}
#Entity
public class Article extends Post {
private String category; // article has category
}
#Entity
public class Journal extends Post {
private Date expiration; // journal has expiration
}
now when I use Spring Jpa Specification to query for articles with certain category, it won't work:
// define specification
public class ArticleSpecifications {
public static Specification<Article> withCategory(String category) {
(root, query, criteriaBuilder) ->
criteriaBuilder.equal(root.get("category"), category)
}
}
// repository
public interface PostRepository<T extends Post> extends JpaRepository<T, Long>, JpaSpecificationExecutor<T> { ... }
// usage: in some service class
#Autowired
private PostRepository<Article> articleRepository;
...
public void someMethod {
...
// error here
articleRepository.findAll(ArticleSpecifications.withCategory("news"), pageable);
...
}
Error message:
java.lang.IllegalArgumentException: Unable to locate Attribute with the the given name [category] on this ManagedType [com.gladdev.galahad.base.BaseEntity]
Just trying to understand here why it tries to look up "category" in BaseEntity.
Every Specification accessing attributes defined in Post works just fine.
Is it some spring jpa specification bug or I missed something?
You can use the CriteriaBuilder.treat() method.
In Criteria API, downcasting an entity to a subclass entity can be performed by using one of the CriteriaBuilder.treat() methods:
See https://docs.oracle.com/javaee/7/api/javax/persistence/criteria/CriteriaBuilder.html#treat-javax.persistence.criteria.Root-java.lang.Class-
public static Specification<Article> withCategory(String category) {
return (root, query, criteriaBuilder) -> {
Root<Article> article = criteriaBuilder.treat(root, Article.class);
return criteriaBuilder.equal(article.get("category"), category);
};
}
I have a base entity class BaseDictionary:
#Entity
#Inheritance
public abstract class BaseDictionary {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
#Column(name = "code")
protected String code;
#Column(name = "is_enabled")
protected Boolean enabled = true;
}
any child classes
#Entity
#Table(name = DB.DIC_RIGHTS_TYPE, schema = DB.SCHEMA_DIC)
public class DicRightsType extends BaseDictionary {}
#Entity
#Table(name = DB.DIC_ROLES_TYPE, schema = DB.SCHEMA_DIC)
public class DicRolesType extends BaseDictionary {}
There are many child classes like this.
Given an entity class name like DicRightsType I would like to get data from the table associated with the entity of that name. How is it possible to implement?
I wanted to use JPA repositories like this: Using generics in Spring Data JPA repositories but this does not suit my case because I only have the name of the entity class at runtime and do not know how to create a dynamic repository for the class.
You can write your own JpaRepository implementation to achieve this.
Step 1: A repository registry
class RepositoryRegistrar {
private static final Map<Class<T>, Repository<T, Serializable>> DICTIONARY = new HashMap<>();
public static void register(Class<T> entityClass, Repository<T, Serializable> repository) {
DICTIONARY.put(entityClass, repository);
}
public static Repository<T, Serializable> get(Class<T> entityClass) {
return DICTIONARY.get(entityClass);
}
}
Step 2: Custom JpaRepository implementation to populate the registry
#NoRepositoryBean
class RegisteringJpaRepository<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> {
public RegisteringJpaRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {{
super(entityInformation, entityManager);
RepositoryRegistrar.register(entityInformation.getJavaType(), this);
}
}
You will have to tweak the configuration to use your custom implementation. Details for this are provided in the Spring Data JPA documentation.
Step 3: Obtain repository references from the registrar
Repository<?, ?> getRepository(String entityClassName) {
return RepositoryRegistrar.get(Class.forName(entityClassName));
}
Folks,
We have really hard time in integrating auditing support in Spring DATA JPA.
We are using spring 3.2.11 and hibernate 4.3.0. (We don't want to use ORM.xml)
Problem is we are not receiving any event in the 'AuditAwareImpl' class when customer entity is saved.
(We debugged AuditingEntityListener and found AuditHandler is getting injected properly but at later point event is not fired. We suspect some class loading issue)
CODE below.
Basically we have two business entity.
#Entity(name = "CUSTOMER")
#Table(name = "CUSTOMER_DETAILS")
#EntityListeners(AuditingEntityListener.class)
public class Customer extends AbstractAuditable<User, Long> {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
User Entity :
#Entity(name = "USER")
#Table(name = "USER_DETAILS")
public class User extends AbstractPersistable<Long>{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
We have one helper class to configure spring.
#Configuration
#EnableTransactionManagement
#EnableJpaAuditing(auditorAwareRef = "auditorAwareImpl")
#EnableJpaRepositories(basePackages = "businessclass")
public class PersistenceContext {
}
AuditAwareImpl.
#Component
public class AuditorAwareImpl implements AuditorAware<User> {
public User getCurrentAuditor() {
ApplicationContext context = ApplicationContextManager.getContext();
UserRepository repository = (UserRepository)context.getBean("userRepository");
User user = new User();
user.setName("work now");
repository.save(user);
return user;
}
}
You need to call the repository's saveAndFlush method.
The save method of org.springframework.data.jpa.repository.JpaRepository supports both save and update. If it is update, it calls em.merge (), but it does not trigger the PreUpdate event. If you want to trigger PreUpdate, you Need to call the saveAndFlush method