I have Users pojo and this pojo is not extend from T.It is like this
#Entity
#Table(name = "USERS")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "USERS.findAll", query = "SELECT s FROM USERS s")})
public class USERS implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected USERSPK usersPK;
#Lob
#Column(name = "Name")
private Stirng name;
#Size(max = 20)
#Column(name = "Surname")
private String surname;
And I wanted to select smth.from this table.Service and DAO classes are below:
public interface CommonService {
public List<Object> hepsiniGetir2(Class persistenceClass, String property, Object searchCrit);
}
This is implementation of interface;
#Service("commonService")
public class CommonServiceImpl implements CommonService, Serializable {
#Transactional
public List<Object> hepsiniGetir2(Class persistenceClass, String property, Object searchCrit) {
return commonDao.findAllByCrit2(persistenceClass, property, searchCrit);
}
}
And here dao interface:
public interface CommonDAO extends GenericDAO<TemelNesne, Long> {
public List<Object> findAllByCrit2(Class persistenceClass, String property, Object searchCrit);
}
Here implementation of dao class:
#Repository
public class CommonDAOImpl extends GenericDAOImpl<TemelNesne, Long> implements CommonDAO {
public List findAllByCrit2(Class persistenceClass, String property, Object searchCrit) {
Criteria c = sessionFactory.getCurrentSession().
createCriteria(persistenceClass).add(Restrictions.eq(property, searchCrit));
List<Object> list = c.list();
if (list.isEmpty()) {
return null;
} else {
return list;
}
}
}
In view class I call this method like ;
#ManagedBean(name="userView", eager=true)
#ViewScoped
public class UserView extends BaseView implements Serializable {
#ManagedProperty("#{commonService}")
private CommonService commonService;
private List<USERS> list;
#PostConstruct
public void init() {
list = (List) commonService.hepsiniGetir2(USERS.class, "name", "Deniz");
}
}
Lastly, I had this exception:
Tem 04, 2014 5:38:10 PM
com.sun.faces.application.view.FaceletViewHandlingStrategy
handleRenderException SEVERE: Error Rendering View[/userList.xhtml]
com.sun.faces.mgbean.ManagedBeanCreationException: An error occurred
performing resource injection on managed bean userView Caused by:
org.hibernate.type.SerializationException: could not deserialize
Caused by: java.io.StreamCorruptedException: invalid stream header:
3C3F786D
Your problem is a concept problem. JSF beans cannot autowire Spring beans, nor the other way around. This is because they are managed in different containers. You should integrate Spring with JSF to allow injection, which basically boils down to Spring controlling everything. There are plenty tutorials in the net about doing this. One good tutorial is mkyong's: JSF 2 + Spring 3 Integration Example. Basically, these are the steps (taken from his tutorial):
In faces-config.xml file, add Expression Language (EL) resolver:
<application>
<el-resolver>
org.springframework.web.jsf.el.SpringBeanFacesELResolver
</el-resolver>
</application>
Instead using JSF annotations, use Spring annotations for JSF managed beans. Example applied to your classes:
#Component("userView")
#Scope("view")
public class UserView extends BaseView implements Serializable {
#Autowired
private CommonService commonService;
private List<USERS> list;
#PostConstruct
public void init() {
list = (List) commonService.hepsiniGetir2(Sertifikalar.class, "name", "Deniz");
}
}
Note that in this example, I'm using #Scope("view") but Spring doesn't have a view scope by default, the team is still working on it. You have to implement this scope manually. Fortunately, you can use Cagatay's implementation to solve this.
Apart of these problems, you have another conceptual problem: the only bean that supports eager=true is #ApplicationScoped since it will work as a #Singleton Spring bean, other managed beans will ignore this attribute at all.
Related
I have about 30 tables that I need to fill from an XML file. And I want to use JPA for that purpose.
Now I have 30 classes annotated with #Entity, config that scans entities and repositories;
Also I have:
#Repository
public interface MyRepository extends JpaRepository<MyEntity1, Long> {
}
And (some controller):
#Autowired
public MyRepository myRepository;
...
...
MyEntity1 entity = new MyEntity(...);
myRepository.save(entity);
It works fine with one #Entity but should I define 30 repositories for that?
I thought I could do something like this:
#Repository
public interface MyRepository<T> extends JpaRepository<T, Long> {
}
and then:
#Autowired
public MyRepository<MyEntity1> myRepository1;
#Autowired
public MyRepository<MyEntity2> myRepository2;
but that gave an error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myRepository1': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class java.lang.Object
Try this approach:
Base class for all entities:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
}
Entities:
#Entity
public class Entity1 extends BaseEntity {
private String name;
}
#Entity
public class Entity2 extends BaseEntity {
private String name;
}
A common repo:
public interface BaseEntityRepo extends JpaRepository<BaseEntity, Long> {
}
Usage:
public class BaseEntityRepoTest extends BaseTest {
#Autowired
private BaseEntityRepo repo;
#Test
public void baseEntityTest() throws Exception {
BaseEntity entity1 = new Entity1("entity1");
BaseEntity entity2 = new Entity2("entity2");
repo.save(entity1);
repo.save(entity2);
List<BaseEntity> entities = repo.findAll();
assertThat(entities).hasSize(2);
entities.forEach(System.out::println);
}
}
Unfortunately you can't do this and you will have to write 30 separate repositories. You can however write generic repositories when the entities share a single table inheritance. (See the answer to Using generics in Spring Data JPA repositories)
What your code is trying to do is make a repository where the shared inheritance is on the class Object which isn't an #Entity hence the exception.
Also an additional minor note, you don't need to annotate your repositories with #Repository. Spring data automatically registers these as beans if it is configured correctly.
As far as I am aware what you are trying is not possible. Spring Data JPA needs an interface per Entity type for its repositories, Because Spring Data JPA will be creating the query implementations.
So it is advised that you have a Repository per Entity as it will allow you to add complex findByXXX methods in the future also.
I have a small application being a bridge between RabbitMQ and SQL database. It is meant to consume events (of few types) from the queue and store them in appropriate tables in the DB. In majority of cases, there is almost no processing between the Event and the Entity (just field copying). This is the reason why I have injected a Dozer mapper that makes the conversion - it works flawlessly. The difficult part is saving a generic object to the repository without having to use switch + instanceof as a last resort.
Code:
#Service
public class EventProcessorImpl implements EventProcessor {
#Autowired
private Mapper mapper; // a Dozer mapper instance
#Override
public void process(final BaseEvent event) {
final BaseEntity entity = mapper.map(event, BaseEntity.class);
// TODO save the entity to the database after it's transformed
}
}
The BaseEntity is a base class for entites, as follows:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BaseEntity {
#Id
private String guid;
public String getGuid() {
return guid;
}
public void setGuid(final String guid) {
this.guid = guid;
}
}
#NoRepositoryBean
public interface BaseRepository<T extends BaseEntity>
extends CrudRepository<T, String> {
}
#Repository
public interface EmailOpenedRepository
extends BaseRepository<EmailOpened> {
}
The question is - how to save the entity, given that:
it is passed as a base class (what I consider as an advantage, but this can be changed)
there are quite a couple of event types (now 5, but can explode to 30 in a few months)
What I have tried:
I have #Autowired an instance of BaseRepository and tried calling repository.save(entity), but it fails on app startup due to multiple bean definitions available.
Based on the question, I have successfully implemented the following, but I don't know whether this is a correct approach:
public void process(final BaseEvent event) {
final BaseEntity entity = mapper.map(event, BaseEntity.class);
final CrudRepository repository = (CrudRepository) new Repositories(context)
.getRepositoryFor(entity.getClass());
repository.save(entity);
}
I thought of iterating over all available beans of BaseRepository and finding the one that will support this type (findFirst(repository -> repository.supports(entity.getType())), but Spring Data JPA repositories are interfaces and I cannot store the supported type in the interface.
I have #Entity classes in an external package that also have static metamodels. In my application's service class, I am using those metamodels and the EntityManager/CriteriaBuilder/CriteriaQuery to retrieve my data. This works fine when running the application. However, when running unit tests, my metamodels and their attributes are always null.
Code...
package com.example.core.entities;
#Entity
#Table(schema = "lookup", name="BookingSystem")
public class BookingSystem implements ILookupEntity, IAuditEntity, Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id")
public Integer id;
#Column(name = "name")
public String name;
#Column(name = "code")
public Integer code;
}
package com.example.core.entities;
#Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
#StaticMetamodel(BookingSystem.class)
public abstract class BookingSystem_ {
public static volatile SingularAttribute<BookingSystem, Integer> id;
public static volatile SingularAttribute<BookingSystem, Integer> code;
public static volatile SingularAttribute<BookingSystem, String> name;
}
Usage in my app's service class...
package com.example.bookingsystem;
#Service
public class BookingService {
#PersistenceContext
private EntityManager entityManager;
public void saveBooking(Booking booking) {
//...
RepositoryQueryBuilder<BookingSystem> bookingSystemSelector = new RepositoryQueryBuilder<>(entityManager, BookingSystem.class);
List<BookingSystem> bookingSystems = bookingSystemSelector
.and(BookingSystem_.code, booking.bookingSystem.code) //<-- Here "BookingSystem_.code" is null.
.getResultList();
//...
}
}
The "RepositoryQueryBuilder" class is just a utility builder class that wraps an EntityManager, CriteriaBuilder, etc. Basically modeled after this example...
JPA Criteria Predicate Conditions
Unit test code...
package com.example.bookingsystem;
public abstract class BaseTestSetup {
#InjectMocks
protected BookingService bookingService;
protected EntityManager entityManager = PowerMockito.mock(EntityManager.class);
protected CriteriaBuilder criteriaBuilder = PowerMockito.mock(CriteriaBuilder.class);
protected CriteriaQuery<BookingSystem> criteriaQuery = PowerMockito.mock(CriteriaQuery.class);
protected Root<BookingSystem> root = PowerMockito.mock(Root.class);
protected void arrange() {
when(entityManager.getCriteriaBuilder()).thenReturn(criteriaBuilder);
when(criteriaBuilder.createQuery(BookingSystem.class)).thenReturn(criteriaQuery);
when(criteriaQuery.from(Matchers.<Class<BookingSystem>>any())).thenReturn(root);
when(criteriaQuery.from(Matchers.<EntityType<BookingSystem>>any())).thenReturn(root);
}
}
#RunWith(PowerMockRunner.class)
public class BookingServiceTest extends BaseTestSetup {
#BeforeClass
#Override
public void arrange() {
super.arrange();
//...
}
#Test
public void doIt() {
Booking booking = new Booking();
booking.id = 12345;
booking.bookingSystem = new BookingSystem();
booking.bookingSystem.id = 1;
booking.bookingSystem.code = 106000;
bookingService.saveBooking(booking);
}
}
I've looked at this JPA/Hibernate Static Metamodel Attributes not Populated -- NullPointerException, but the solution seems to be "make sure that the entity and its metamodel are in the same package", but as you can see, both are already in my "com.example.core.entities" package.
I'm using all bean and annotation driven configruation in my code (no persistence or context xml files). As far as testing goes, I'm using TestNG and PowerMock from within IntelliJ.
It just seems as if the metamodels aren't being picked up during unit tests. Any ideas.
The static metamodel classes are populated when hibernate is loaded. So, either you configure hibernate context in your test or you populate the attributes manually before the method execution. In you code, you could do:
#Test
public void doIt() {
BookingSystem_.code = new SingularAttributeMock<BookingSystem, Integer>();
bookingService.saveBooking(booking);
}
}
The class SingularAttributeMock can be created custom-made in order to use it in your tests. You can also use any other implementation of the SingularAttribute class.
public class SingularAttributeMock<X, Y> implements SingularAttribute<X, Y> {
//Overriding methods of SingularAttribute...
}
Instead of creating own class, I suggest making Mockito to do the job for you.
#Mock // declare a mock along the others you might have
private SingularAttribute<BookingSystem, Integer> code;
#Before
public void setUp() throws Exception {
// fill metamodel with it
BookingSystem_.code = code;
}
Worth to mention however that bringing metamodels to service layer is not very good practice, you would rather push them down to DAO methods.
There is no need to manual initialization.
You should observe following rules :
Metamodel classes should declared as abstract class.
Metamodel classes should be in the same package as the entity classes they
describe;
They should have the same name as the entity classes they
describe, followed by an underscore (e.g. Product is the entity,
Product_ is the metamodel class);
If an entity inherits from another
entity or from a mapped superclass, its metamodel class should
inherit from the metamodel class that describes its immediate
superclass (e.g. if SpecialProduct extends Product, which extends
PersistentObject, then SpecialProduct_ should extend Product_ which
should extend PersistentObject_).
In my case, mock the metamodel doesn't worked, so I just get it from entityManager.
private EntityManager entityManager;
#Before
public void init() {
// Assume that entityManager was correctly initialized.
this.configMetaModel();
}
private void configMetaModel() {
Metamodel metamodel = this.entityManager.getMetamodel();
BiFunction<EntityType<MY_ENTITY>, String, Attribute>
bfAttr = (entity, field) -> entity.getAttributes()
.stream()
.filter(a -> a.getName().equals(field))
.findAny()
.get();
Function<Attribute, SingularAttribute<MY_ENTITY, String>> fToStr = attribute ->
(SingularAttribute<MY_ENTITY, String>) attribute;
Function<Attribute, SingularAttribute<MY_ENTITY, LocalDate>> fToDate = attribute ->
(SingularAttribute<MY_ENTITY, LocalDate>) attribute;
EntityType<MY_ENTITY> entity = metamodel.entity(MY_ENTITY.class);
MY_ENTITY_.id = fToStr.apply(bfAttr.apply(entity, "id"));
MY_ENTITY_.name = fToStr.apply(bfAttr.apply(entity, "name"));
MY_ENTITY_.someDate = fToDate.apply(bfAttr.apply(entity, "someDate"));
}
"MY_ENTITY" replace my entity
"MY_ENTITY_" replace my entity metamodel
Once I did this, I could run all my unit test perfectly.
I'm using Hibernate in a Spring Boot app. I'm making a new CrudRepository for all my Model objects, to do basic CRUD tasks. They look like this:
#Repository
public interface FoobarCrudRepo extends CrudRepository<Foobar, Long> {
}
But then I always need to do some additional things, like custom search queries with inequalities and such. I follow a pattern like this:
#Repository
public class FoobarDao {
#PersistenceContext
EntityManager em;
public List<Foobar> findFoobarsByDate(Date date) {
String sql = "select fb from Foobar fb where createdDate > :date";
...
return query.getResultList();
}
}
My question is, can I combine these two concepts into a single class? I tried making it an abstract class, like so:
#Repository
public abstract class FoobarCrudRepo extends CrudRepository<Foobar, Long> {
#PersistenceContext
EntityManager em;
public List<Foobar> findFoobarsByDate(Date date) {
String sql = "select fb from Foobar fb where createdDate > :date";
...
return query.getResultList();
}
}
But then Spring didn't create a bean for it.
How can I accomplish this?
Thanks!
There are lots of ways you could probably accomplish this. If you really need absolute control try this
interface FoobarRepositoryCustom{
List<Foobar> findFoobarsByDate(Date date);
}
interface FoobarRepository extends CrudRepository<Foobar, Long>, FoobarRepositoryCustom
public class FoobarRespoitoryImpl implements FoobarRepositoryCustom{
#PersistenceContext private EntityManager em;
public List<Foobar> findFoobarsByDate(Date date) {
String sql = "select fb from Foobar fb where createdDate > :date";
...
return query.getResultList();
}
}
There is also the possibility to go a simpler route and the query can be auto generated for you based on the method name. In your example you could just add this to your FoobarCrudRepo and Spring should do the rest assuming Foobar has a property named CreatedDate
List<Foobar> findByCreatedDateGreaterThan(Date date);
For reference on how Spring can generate queries based on the method name see this http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
Completely new to Spring Data, but having searched a bit it is my impression that you do not have to leave the interface to create custom logic - rather you would create either an annotated interface method, an interface method that follows a special naming scheme or a default interface method with custom logic:
Screenshot from Baeldung: Introduction to Spring.
Here is a link to the documentation. Notice "table 4. Supported keywords inside method names" which can be used to create interface methods, whose name conveys information to the code generator about which query to create (See part of table below).
The problem here is abstract keyword.
#Repository
public abstract class FoobarCrudRepo extends CrudRepository<Foobar, Long>
Spring will not create a bean for a class unless it is a concrete class.
That's why you are getting a bean for it.
This is what worked for me...
#SpringBootApplication(scanBasePackages = { "com.myproject" })
#EnableJpaRepositories(basePackages="com.myproject.sprinbootapp.repository")
#EntityScan("com.myproject.sprinbootapp.model")
public class SpringbootAppWithDatabaseApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootAppWithDatabaseApplication.class, args);
}
}
#Service
public class TopicService {
#Autowired
private TopicRepository topicRepository;
private List<Topics> topics = new ArrayList<Topics>();
public List<Topics> getAllTopics(){
List<Topics> listOfTopics = new ArrayList<Topics>();
topicRepository.findAll().forEach(listOfTopics::add);;
return listOfTopics;
}
}
#Entity
public class Topics {
#Id
private String id;
private String name;
public Topics(){
}
getters and setters...
}
public interface TopicRepository extends CrudRepository<Topics, String> {
}
we can use the JPA EntityManager for direct sql actions:
public interface VerificationsRepository extends
CrudRepository<Verification, Integer>,
DAOAccess
{ }
interface DAOAccess {
List findByEmail(String email);
}
class DAOAccessImpl implements DAOAccess {
#PersistenceContext private EntityManager em;
public List findByEmail(String email) {
String sql =
"select * from verifications where email = ?";
Query query = em.createNativeQuery(sql, Verification.class)
.setParameter(1, email);
return query.getResultList();
}
}
I am using Spring Data for MongoDB and I need to be able to configure collection at runtime.
My repository is defined as:
#Repository
public interface EventDataRepository extends MongoRepository<EventData, String> {
}
I tried this silly example:
#Document(collection = "${mongo.event.collection}")
public class EventData implements Serializable {
but mongo.event.collection did not resolve to a name as it does with a #Value annotation.
A bit more debugging and searching and I tried the following:
#Document(collection = "#{${mongo.event.collection}}")
This produced an exception:
Caused by: org.springframework.expression.spel.SpelParseException: EL1041E:(pos 1): After parsing a valid expression, there is still more data in the expression: 'lcurly({)'
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.doParseExpression(InternalSpelExpressionParser.java:129)
at org.springframework.expression.spel.standard.SpelExpressionParser.doParseExpression(SpelExpressionParser.java:60)
at org.springframework.expression.spel.standard.SpelExpressionParser.doParseExpression(SpelExpressionParser.java:32)
at org.springframework.expression.common.TemplateAwareExpressionParser.parseExpressions(TemplateAwareExpressionParser.java:154)
at org.springframework.expression.common.TemplateAwareExpressionParser.parseTemplate(TemplateAwareExpressionParser.java:85)
Perhaps I just don't know how to quite use SPel to access values from Spring's Property Configurer.
When stepping through the code, I see that there is a way to specify collection name or even expressions, however, I am not sure which annotation should be used for this purpose or how to do it.
Thanks.
-AP_
You can solve this problem by just using SPeL:
#Document(collection = "#{environment.getProperty('mongo.event.collection')}")
public class EventData implements Serializable {
...
}
Update Spring 5.x:
Since Spring 5.x or so you need an additional # before environment:
#Document(collection = "#{#environment.getProperty('mongo.event.collection')}")
public class EventData implements Serializable {
...
}
Docs:
SpEL: 4.2 Expressions in Bean Definitions
SpEL: 4.3.12 Bean References
PropertyResolver::getProperty
So, at the end, here is a work around that did the trick. I guess I really don't know how to access data from Spring Properties Configurer using the SPeL expressions.
In my #Configuration class:
#Value("${mongo.event.collection}")
private String
mongoEventCollectionName;
#Bean
public String mongoEventCollectionName() {
return
mongoEventCollectionName;
}
On my Document:
#Document(collection = "#{mongoEventCollectionName}")
This, appears to work and properly pick up the name configured in my .properties file, however, I am still not sure why I could not just access the value with $ as I do in the #Value annotation.
define your entity class like
#Document(collection = "${EventDataRepository.getCollectionName()}")
public class EventData implements Serializable {
Define a custom repository interface with getter and setter methods for "collectionName"
public interface EventDataRepositoryCustom {
String getCollectionName();
void setCollectionName(String collectionName);
}
provide implementation class for custom repository with "collectionName" implementation
public class EventDataRepositoryImpl implements EventDataRepositoryCustom{
private static String collectionName = "myCollection";
#Override
public String getCollectionName() {
return collectionName;
}
#Override
public void setCollectionName(String collectionName) {
this.collectionName = collectionName;
}
}
Add EventDataRepositoryImpl to the extends list of your repository interface in this it would look like
#Repository
public interface EventDataRepository extends MongoRepository<EventData, String>, EventDataRepositoryImpl {
}
Now in your Service class where you are using the MongoRepository set the collection name, it would look like
#Autowired
EventDataRepository repository ;
repository.setCollectionName("collectionName");
Entity Class
#Document // remove the parameters from here
public class EscalationCase
{
}
Configuration class
public class MongoDBConfiguration {
private final Logger logger = LoggerFactory.getLogger(MongoDBConfiguration.class);
#Value("${sfdc.mongodb.collection}") //taking collection name from properties file
private String collectionName;
#Bean
public MongoTemplate mongoTemplate(MongoDbFactory mongoDbFactory, MongoMappingContext context) {
MappingMongoConverter converter = new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory), context);
converter.setTypeMapper(new DefaultMongoTypeMapper(null));
MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory, converter);
if (!mongoTemplate.collectionExists(collectionName)) {
mongoTemplate.createCollection(collectionName); // adding the collection name here
}
return mongoTemplate;
}
}