Skip to content

Commit e12b8d0

Browse files
committed
test: add test case demonstrating projection issue with non-String fields
- Created test entity with mixed field types (Integer, Double, Boolean, LocalDate) - Added projection interfaces with and without @value annotations - Test shows that non-String fields require @value annotation to work properly - The workaround of using @value annotation works as expected This test documents the behavior described in issue #650 where projection interfaces return null for non-String fields unless @value annotation is used. Related to #650
1 parent 2b9d87e commit e12b8d0

File tree

5 files changed

+217
-0
lines changed

5 files changed

+217
-0
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.redis.om.spring.fixtures.document.model;
2+
3+
import com.redis.om.spring.annotations.Document;
4+
import com.redis.om.spring.annotations.Indexed;
5+
import lombok.AllArgsConstructor;
6+
import lombok.Builder;
7+
import lombok.Data;
8+
import lombok.NoArgsConstructor;
9+
import org.springframework.data.annotation.Id;
10+
11+
import java.time.LocalDate;
12+
13+
@Document
14+
@Data
15+
@NoArgsConstructor
16+
@AllArgsConstructor
17+
@Builder
18+
public class DocumentWithMixedTypes {
19+
20+
@Id
21+
private String id;
22+
23+
@Indexed
24+
private String name;
25+
26+
@Indexed
27+
private Integer age;
28+
29+
@Indexed
30+
private Double salary;
31+
32+
@Indexed
33+
private Boolean active;
34+
35+
@Indexed
36+
private LocalDate birthDate;
37+
38+
private String description;
39+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.redis.om.spring.fixtures.document.repository;
2+
3+
import java.time.LocalDate;
4+
5+
/**
6+
* Projection interface WITHOUT @Value annotations to demonstrate the issue
7+
* where non-String fields return null
8+
*/
9+
public interface DocumentMixedTypesProjection {
10+
11+
// String fields should work without @Value
12+
String getName();
13+
14+
// Non-String fields will return null without @Value annotation
15+
Integer getAge();
16+
17+
Double getSalary();
18+
19+
Boolean getActive();
20+
21+
LocalDate getBirthDate();
22+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.redis.om.spring.fixtures.document.repository;
2+
3+
import org.springframework.beans.factory.annotation.Value;
4+
5+
import java.time.LocalDate;
6+
7+
/**
8+
* Projection interface WITH @Value annotations as a workaround
9+
* to make non-String fields work correctly
10+
*/
11+
public interface DocumentMixedTypesProjectionFixed {
12+
13+
// String fields work without @Value
14+
String getName();
15+
16+
// Non-String fields need @Value annotation to work
17+
@Value("#{target.age}")
18+
Integer getAge();
19+
20+
@Value("#{target.salary}")
21+
Double getSalary();
22+
23+
@Value("#{target.active}")
24+
Boolean getActive();
25+
26+
@Value("#{target.birthDate}")
27+
LocalDate getBirthDate();
28+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.redis.om.spring.fixtures.document.repository;
2+
3+
import com.redis.om.spring.fixtures.document.model.DocumentWithMixedTypes;
4+
import com.redis.om.spring.repository.RedisDocumentRepository;
5+
6+
import java.util.Optional;
7+
8+
public interface DocumentMixedTypesRepository extends RedisDocumentRepository<DocumentWithMixedTypes, String> {
9+
10+
// Return the entity first to verify data exists
11+
Optional<DocumentWithMixedTypes> findByName(String name);
12+
13+
// Return projection without @Value annotations
14+
Optional<DocumentMixedTypesProjection> findFirstByName(String name);
15+
16+
// Return projection with @Value annotations
17+
Optional<DocumentMixedTypesProjectionFixed> findOneByName(String name);
18+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package com.redis.om.spring.repository;
2+
3+
import com.redis.om.spring.AbstractBaseDocumentTest;
4+
import com.redis.om.spring.fixtures.document.model.DocumentWithMixedTypes;
5+
import com.redis.om.spring.fixtures.document.repository.DocumentMixedTypesProjection;
6+
import com.redis.om.spring.fixtures.document.repository.DocumentMixedTypesProjectionFixed;
7+
import com.redis.om.spring.fixtures.document.repository.DocumentMixedTypesRepository;
8+
import org.junit.jupiter.api.AfterEach;
9+
import org.junit.jupiter.api.BeforeEach;
10+
import org.junit.jupiter.api.Test;
11+
import org.springframework.beans.factory.annotation.Autowired;
12+
13+
import java.time.LocalDate;
14+
import java.util.Optional;
15+
16+
import static org.junit.jupiter.api.Assertions.*;
17+
18+
/**
19+
* Test to reproduce and demonstrate issue #650:
20+
* Projection interfaces return null for non-String fields when not using @Value annotation
21+
*/
22+
class DocumentProjectionMixedTypesTest extends AbstractBaseDocumentTest {
23+
24+
@Autowired
25+
private DocumentMixedTypesRepository repository;
26+
27+
private DocumentWithMixedTypes testEntity;
28+
29+
@BeforeEach
30+
void setUp() {
31+
testEntity = DocumentWithMixedTypes.builder()
32+
.name("John Doe")
33+
.age(30)
34+
.salary(75000.50)
35+
.active(true)
36+
.birthDate(LocalDate.of(1993, 5, 15))
37+
.description("Test employee")
38+
.build();
39+
40+
testEntity = repository.save(testEntity);
41+
}
42+
43+
@Test
44+
void testEntityFetch_VerifyDataExists() {
45+
// First verify the entity exists with proper data
46+
Optional<DocumentWithMixedTypes> entity = repository.findByName("John Doe");
47+
48+
assertTrue(entity.isPresent(), "Entity should be found by name");
49+
assertEquals("John Doe", entity.get().getName());
50+
assertEquals(30, entity.get().getAge());
51+
assertEquals(75000.50, entity.get().getSalary());
52+
assertTrue(entity.get().getActive());
53+
assertEquals(LocalDate.of(1993, 5, 15), entity.get().getBirthDate());
54+
}
55+
56+
@Test
57+
void testProjectionWithoutValueAnnotation_NonStringFieldsReturnNull() {
58+
// This test demonstrates the issue - non-String fields return null without @Value
59+
Optional<DocumentMixedTypesProjection> projection = repository.findFirstByName("John Doe");
60+
61+
assertTrue(projection.isPresent(), "Projection should be present");
62+
63+
// String field should work
64+
assertEquals("John Doe", projection.get().getName(), "String field should work without @Value");
65+
66+
// These assertions demonstrate the issue - all non-String fields return null
67+
assertNull(projection.get().getAge(),
68+
"Integer field returns null without @Value annotation - this is the issue!");
69+
assertNull(projection.get().getSalary(),
70+
"Double field returns null without @Value annotation - this is the issue!");
71+
assertNull(projection.get().getActive(),
72+
"Boolean field returns null without @Value annotation - this is the issue!");
73+
assertNull(projection.get().getBirthDate(),
74+
"LocalDate field returns null without @Value annotation - this is the issue!");
75+
}
76+
77+
@Test
78+
void testProjectionWithValueAnnotation_AllFieldsWork() {
79+
// Test that all fields work correctly with @Value annotation (the workaround)
80+
Optional<DocumentMixedTypesProjectionFixed> projection = repository.findOneByName("John Doe");
81+
82+
assertTrue(projection.isPresent(), "Projection should be present");
83+
84+
// All fields should work with @Value annotation
85+
assertEquals("John Doe", projection.get().getName(), "String field should work");
86+
assertEquals(30, projection.get().getAge(), "Integer field should work with @Value");
87+
assertEquals(75000.50, projection.get().getSalary(), "Double field should work with @Value");
88+
assertTrue(projection.get().getActive(), "Boolean field should work with @Value");
89+
assertEquals(LocalDate.of(1993, 5, 15), projection.get().getBirthDate(),
90+
"LocalDate field should work with @Value");
91+
}
92+
93+
@Test
94+
void testDirectEntityFetch_AllFieldsWork() {
95+
// Verify that the entity itself has all fields correctly stored
96+
Optional<DocumentWithMixedTypes> entity = repository.findById(testEntity.getId());
97+
98+
assertTrue(entity.isPresent(), "Entity should be present");
99+
assertEquals("John Doe", entity.get().getName());
100+
assertEquals(30, entity.get().getAge());
101+
assertEquals(75000.50, entity.get().getSalary());
102+
assertTrue(entity.get().getActive());
103+
assertEquals(LocalDate.of(1993, 5, 15), entity.get().getBirthDate());
104+
}
105+
106+
@AfterEach
107+
void tearDown() {
108+
repository.deleteAll();
109+
}
110+
}

0 commit comments

Comments
 (0)