-1

I got an exception when I try to basically read a @ManyToMany relation using ebean cache system (with io.ebean:ebean-redis). This is a SpringBoot application.

The versions I am using:

  • springBootVersion=2.4.3
  • mariaDbVersion=2.7.2
  • ebeanVersion=12.7.2
  • flywayVersion=7.7.0

The BaseModel Java class:

@MappedSuperclass
public abstract class BaseModel extends Model {

    @Id
    @GeneratedValue
    private Long id;

    @WhenCreated
    @NotNull
    private Instant createdAt;

    @WhenModified
    @NotNull
    private Instant updatedAt;

    @NotNull
    @SoftDelete
    private Boolean deleted = false;

    protected BaseModel() {
    }

    // here the getters and setters
}

The Article Java class:

@Entity
@Table(name = "article")
@Cache
public class DArticle extends BaseModel {

    private static final long serialVersionUID = -7120023327129825322L;

    @NotNull
    @Index
    @Length(20)
    private String code;

    @DbJson
    @NotNull
    private Map<Locale, String> name;

    @NotNull
    private Double unitPrice;

    @ManyToMany(mappedBy = "articles")
    private List<DArticleCategory> articleCategories;

    public DArticle(String code, Map<Locale, String> name, Double unitPrice) {
        super();
        this.code = code;
        this.name = name;
        this.unitPrice = unitPrice;
    }

    // here the getters and setters
}

The ArticleCategory Java class:

@Entity
@Table(name = "article_category")
@Cache
public class DArticleCategory extends BaseModel {

    private static final long serialVersionUID = 528512691717594544L;

    @DbJson
    @NotNull
    private Map<Locale, String> name;

    @ManyToMany
    private List<DArticle> articles;

    public DArticleCategory(Map<Locale, String> name) {
        super();
        this.name = name;
    }

    // here the getters and setters

}

The SQL (I use flyway for the migrations):

create table `article` (
  `id`                            bigint auto_increment not null,
  `created_at`                    datetime(6) not null,
  `updated_at`                    datetime(6) not null,
  `deleted`                       tinyint(1) not null,
  `code`                          varchar(20) not null,
  `name`                          longtext not null,
  `unit_price`                    double not null,
  primary key (`id`),
  index (`code`)
);

create table `article_category` (
  `id`                            bigint auto_increment not null,
  `created_at`                    datetime(6) not null,
  `updated_at`                    datetime(6) not null,
  `deleted`                       tinyint(1) not null,
  `name`                          longtext not null,
  primary key (`id`)
);

The code I try to execute:

DArticleCategory c = new DArticleCategory(getTranslatedText("Category 1", "Catégorie 1", null));
c.save();

DArticleCategory cat = articleCategoryRepository.findById(1l);
for (DArticle article : cat.getArticles()) {
    //nothing
}

The exception:

Caused by: java.lang.RuntimeException: Failed to decode cache data
    at io.ebean.redis.encode.EncodePrefixKey.encode(EncodePrefixKey.java:26)
    at io.ebean.redis.RedisCache.key(RedisCache.java:85)
    at io.ebean.redis.RedisCache.get(RedisCache.java:139)
    at io.ebeaninternal.server.deploy.BeanDescriptorCacheHelp.manyPropGet(BeanDescriptorCacheHelp.java:277)
    at io.ebeaninternal.server.deploy.BeanDescriptorCacheHelp.manyPropLoad(BeanDescriptorCacheHelp.java:297)
    at io.ebeaninternal.server.deploy.BeanDescriptor.cacheManyPropLoad(BeanDescriptor.java:1306)
    at io.ebeaninternal.server.loadcontext.DLoadManyContext$LoadBuffer.loadMany(DLoadManyContext.java:215)
    at io.ebean.common.AbstractBeanCollection.lazyLoadCollection(AbstractBeanCollection.java:101)
    at io.ebean.common.BeanList.init(BeanList.java:139)
    at io.ebean.common.BeanList.iterator(BeanList.java:335)
    at db.migration.dev.V2_0_1__katel_test.migrate(V2_0_1__katel_test.java:200)
    at org.flywaydb.core.internal.resolver.java.JavaMigrationExecutor.executeOnce(JavaMigrationExecutor.java:61)
    ... 59 common frames omitted
Caused by: java.lang.IllegalStateException: Expecting String keys but got type:class java.lang.Long
    at io.ebean.redis.encode.EncodePrefixKey.encode(EncodePrefixKey.java:19)
    ... 70 common frames omitted

It looks a very simple code, but I'm not able to see where I'm wrong...

jkohler
  • 1
  • 1
  • What is the code at: db.migration.dev.V2_0_1__katel_test.migrate(V2_0_1__katel_test.java:200) ? – Rob Bygrave Mar 25 '21 at 11:30
  • If you create a test case I don't mind having a look etc. – Rob Bygrave Mar 25 '21 at 11:34
  • Hi Rob, the line 200 is "for (DArticle article : cat.getArticles()) {", that's the cat.getArticles() which trigger the exception. I finally revert all my code related to the cache, because I faces other issues. probably related to a misunderstanding from my part, I will dig that later. But my above problem still strange because there is not much complexity. Anyway many thanks for your help! – jkohler Mar 26 '21 at 12:17

1 Answers1

0

The annotation @Cacheable is only available for public exposed method that are allowed to be intercepter. But you could get the "CacheManager" services and use it in your code to handle internally the cache in the privated methods if required. But only to solve some "special" problems the usual way is to annotate the public methods.

Also if you use only the starter you are using only the basic and poor implementation of Spring, a simple memory cache.

Think about how your application will work (single app, distributed app, short/long amount of data cached,...) and the memory consumption to add a dependency of any of the supported cache managers like ehCache, Hazelcast,Caffeine,... that meets your requirements and improves your cache performance.

  • Thanks Sebastian! To complete my question, I'm using ebean-redis (io.ebean:ebean-redis) with a local redis (docker). When I manually read redis, everything is fine. In your answer, you mention @Cacheable, is it similar than than io.ebean.annotation.@Cache in terms of behavior? Also all my fields have getters and setters, I suppose than ebean handle them (by looking their code, seems true)? Finally, thanks for the recommendation for supported caches, indeed I will dig into in a second phase, mainly for caching REST services. – jkohler Mar 19 '21 at 14:55