Search code examples
spring-bootspring-data-jpahqlhexagonal-architecture

JPA Entity is not mapped


I have Spring microservicies application using hexagonal architecture. When try to get data from my H2 database using hql query I have an exception which say my Entity is not mapped. My Entity is subclass of another one who have commons attribute.

package com.package.infrastructure.repository.jpa.entity.nomenclature;

import lombok.Data;

import javax.persistence.*;

@Data
@MappedSuperclass
public class NomenclatureEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(length = 50)
    private String label;
}

Activity

package com.package.company.infrastructure.repository.jpa.entity.nomenclature;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;

import javax.persistence.Entity;

@Data
@EqualsAndHashCode
@ToString
@Entity(name = "N_ACTIVITY")
public class ActivityEntity extends NomenclatureEntity {
}

repository

package com.package.company.infrastructure.repository.jpa;

import com.package.company.infrastructure.repository.jpa.entity.nomenclature.NomenclatureEntity;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface NomenclatureSpringDataRepository extends CrudRepository<NomenclatureEntity, Long> {
}

Spring data implementation

package com.package.company.infrastructure.repository.jpa;

import com.package.company.core.NomenclatureRepository;
import com.package.company.core.model.nomenclature.*;
import com.package.company.infrastructure.repository.jpa.entity.nomenclature.*;
import com.package.company.infrastructure.repository.jpa.mapping.nomenclature.*;
import org.mapstruct.factory.Mappers;
import org.springframework.transaction.annotation.Transactional;

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

@Transactional(readOnly = true)
public class NomenclatureRepositorySpringDataWrapper implements NomenclatureRepository {

    NomenclatureSpringDataRepository nomenclatureSpringDataRepository;

    @PersistenceContext
    private EntityManager entityManager;

    public NomenclatureRepositorySpringDataWrapper(NomenclatureSpringDataRepository nomenclatureSpringDataRepository) {
        this.nomenclatureSpringDataRepository = nomenclatureSpringDataRepository;
    }

    @Override
    public List<Activity> getAllActivity() {
        Query query = entityManager.createQuery("SELECT a FROM ActivityEntity a");
        List<ActivityEntity> activityEntities = query.getResultList();
        ActivityEntityMapper mapper = Mappers.getMapper(ActivityEntityMapper.class);
        List<Activity> activities = activityEntities.stream().map(ae->mapper.toNomenclature(ae)).collect(Collectors.toList());
        return activities;
    }
}

start class

package com.package;

import com.package.core.NomenclatureRepository;
import com.package.core.model.nomenclature.*;
import com.package.infrastructure.config.CompanyApplicationConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;

@SpringBootApplication(exclude={SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class})
@Import(value = MyApplicationConfig.class)
public class MyApplication {

    @Autowired
    private NomenclatureRepository nomenclatureRepository;

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

    @Bean
    public CommandLineRunner init(){
        return (String... args)->{
            nomenclatureRepository.saveActivity(new Activity(1L, "Activity 1"));
            nomenclatureRepository.saveActivity(new Activity(2L, "Activity 2"));
        };
    }
}

Result

2021-07-01 10:29:08.118 ERROR 9224 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: ActivityEntity is not mapped [SELECT a FROM ActivityEntity a]] with root cause

org.hibernate.hql.internal.ast.QuerySyntaxException: ActivityEntity is not mapped
    at org.hibernate.hql.internal.ast.util.SessionFactoryHelper.requireClassPersister(SessionFactoryHelper.java:169) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
    at org.hibernate.hql.internal.ast.tree.FromElementFactory.addFromElement(FromElementFactory.java:91) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]

Solution

  • You have used @Entity(name = "N_ACTIVITY") to class ActivityEntity. The name in @Entity is for JPA-QL queries, it defaults to the class name if no value is provided, but since you changed it you have to make sure you use this name when building queries.

    So either your query should be updated as follows:

    SELECT a FROM N_ACTIVITY a
    

    or you can remove the name and use the class name ActivityEntity