Skip to content

Commit

Permalink
ListArrayTypeDescriptor doesn't support Spring JPA Projections #562
Browse files Browse the repository at this point in the history
  • Loading branch information
SergeiKhmelevSPA authored and vladmihalcea committed Feb 16, 2023
1 parent 96335e4 commit 7e39ae3
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 0 deletions.
Expand Up @@ -151,6 +151,10 @@ public void setParameterValues(Properties parameters) {
}

private Collection newPropertyCollectionInstance() {
// propertyClass is not defind for the projection
if(propertyClass == null){
return new ArrayList();
}
if(List.class.isAssignableFrom(propertyClass)) {
return new ArrayList();
} else if(Set.class.isAssignableFrom(propertyClass)) {
Expand Down
@@ -0,0 +1,31 @@
package io.hypersistence.utils.spring.repo.projection;

import io.hypersistence.utils.spring.domain.Post;
import io.hypersistence.utils.spring.repository.BaseJpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import javax.annotation.Nullable;
import java.util.List;

/**
* @author Vlad Mihalcea
*/
@Repository
public interface PostRepository extends BaseJpaRepository<Post, Long> {

@Query(value = "select p.title as title, array_agg(p.slug) as slugs " +
"from Post p " +
"group by p.title",
nativeQuery = true)
@Nullable
List<TestProjection> findAllSlugGroupedByTitle();


interface TestProjection {
@Nullable
String getTitle();
@Nullable
List<String> getSlugs();
}
}
@@ -0,0 +1,45 @@
package io.hypersistence.utils.spring.repo.projection;

import io.hypersistence.utils.hibernate.type.array.ListArrayType;
import io.hypersistence.utils.spring.config.AbstractSpringDataJPAConfiguration;
import io.hypersistence.utils.spring.domain.Post;
import io.hypersistence.utils.spring.repository.BaseJpaRepositoryImpl;
import org.hibernate.boot.spi.MetadataBuilderContributor;
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

import java.util.Properties;

/**
* @author Vlad Mihalcea
*/
@ComponentScan(
basePackages = {
"io.hypersistence.utils.spring.repo.projection",
}
)
@EnableJpaRepositories(
value = "io.hypersistence.utils.spring.repo.projection",
repositoryBaseClass = BaseJpaRepositoryImpl.class
)
public class ProjectionSpringDataJPABaseConfiguration extends AbstractSpringDataJPAConfiguration {

@Override
protected String packageToScan() {
return Post.class.getPackage().getName();
}

@Override
protected void additionalProperties(Properties properties) {
properties.put("hibernate.jdbc.batch_size", "100");
properties.put("hibernate.order_inserts", "true");

properties.put(
EntityManagerFactoryBuilderImpl.METADATA_BUILDER_CONTRIBUTOR,
(MetadataBuilderContributor) metadataBuilder -> metadataBuilder.applyBasicType(
ListArrayType.INSTANCE
)
);
}
}
@@ -0,0 +1,79 @@
package io.hypersistence.utils.spring.repo.projection;

import io.hypersistence.utils.hibernate.type.util.Configuration;
import io.hypersistence.utils.spring.domain.Post;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static org.junit.Assert.assertEquals;

/**
* @author Vlad Mihalcea
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ProjectionSpringDataJPABaseConfiguration.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class ProjectionSpringDataJPABaseTest {

protected final Logger LOGGER = LoggerFactory.getLogger(getClass());

@Autowired
private TransactionTemplate transactionTemplate;

@Autowired
private PostRepository postRepository;

@PersistenceContext
private EntityManager entityManager;

@Test
public void myTest() {
// given
transactionTemplate.execute((TransactionCallback<Void>) transactionStatus -> {
postRepository.persist(
new Post()
.setId(1L)
.setTitle("test title")
.setSlug("slug1")
);

postRepository.persistAndFlush(
new Post()
.setId(2L)
.setTitle("test title")
.setSlug("slug2")
);

return null;
});

// when
List<PostRepository.TestProjection> postsSummary = transactionTemplate.execute(transactionStatus ->
postRepository.findAllSlugGroupedByTitle()
);

// then
PostRepository.TestProjection result = postsSummary.get(0);
assertEquals("test title", result.getTitle());

List<String> expectedSlugs = new ArrayList<>();
expectedSlugs.add("slug1");
expectedSlugs.add("slug2");
assertEquals(expectedSlugs, result.getSlugs());
}
}

0 comments on commit 7e39ae3

Please sign in to comment.