redis / redis-om-spring

Spring Data Redis extensions for better search, documents models, and more
MIT License
609 stars 94 forks source link

EntityStream .project() throws exception because of private fields. #491

Closed xMilos closed 4 months ago

xMilos commented 4 months ago

I am getting com.redis.om.spring.search.stream.SearchStreamImpl - 🧨 couldn't set value on id java.lang.IllegalAccessException: class com.redis.om.spring.search.stream.SearchStreamImpl cannot access a member of class com.test.ExampleRedis with modifiers "private"

I am on 0.8.7 version.

   @Override
    public <E> Set<E> findAllFields(Class<E> clazz, Pageable pageable, MetamodelField<E, ?>... fields) {
        Set<E> collect = entityStream.of(clazz)
                .skip(pageable.getPageNumber()) // page number
                .limit(pageable.getPageSize()) // page size
                .project(fields)
                .collect(Collectors.toSet());
        return collect;
    }

Document:

@Data
@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor
@Document
public class ExampleRedis {
    @Id
    private Long id;
    @NumericIndexed
    private Integer isDeleted;
    ... other fields
}
    @Test
    void testGetAllRedisGeneric() {
        Set<ExampleRedis> data = redisRepository.findAllFields(ExampleRedis.class, PageRequest.of(0, 50_000), ExampleRedis$.ID, ExampleRedis$.IS_DELETED);
        assertEquals(50_000, data.size()));
    }

What am i doing wrong, I followed this example: https://github.com/redis/redis-om-spring/blob/main/redis-om-spring/src/test/java/com/redis/om/spring/search/stream/EntityStreamDocsTest.java#L2613, in Doc3 class fields are also private.

Also is this the correct way to return only the fields I need from the document ?

bsbodden commented 4 months ago

@xMilos if you look at the entity Doc3 you'll notice that it has the @Data annotation from Lombok which gives it getters/setters for the private fields. So just like other Spring entities your objects need to follow the JavaBean spec, that is you need to have getters/setters on them

xMilos commented 4 months ago

Yes I already use @Data from lombok, also tried setting @Getter @Setter on the fields

bsbodden commented 4 months ago

uhmm, can you create a small reproducer and I'll take a look at it, could be a bug, but it looks just like that example that works. Either way post it right here and I'll figure it out. Cheers.

xMilos commented 4 months ago

https://github.com/redis/redis-om-spring/blob/main/redis-om-spring/src/main/java/com/redis/om/spring/search/stream/SearchStreamImpl.java#L564 inside the .set(

    @CallerSensitive
    @ForceInline // to ensure Reflection.getCallerClass optimization
    public void set(Object obj, Object value)
        throws IllegalArgumentException, IllegalAccessException
    {
        if (!override) {
            Class<?> caller = Reflection.getCallerClass();
            checkAccess(caller, obj);
        }
        getFieldAccessor(obj).set(obj, value);
    }

here override is true in your tests, in my app this is false, do you know where you set this to true ? Or why aren't the setters used ?

bsbodden commented 4 months ago

@xMilos I just got back from Holiday... were you able to resolve this?

xMilos commented 4 months ago

Couldn't replicate it in example project https://github.com/xMilos/redis-om-test, for some reason in our app the private fields are not accessible, like a mentioned that override flag there is false on debug. If I can replicate the issue I will reopen this one.