ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 01.01.2026

Просмотров: 2627

Скачиваний: 0

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

Vaadin JPAContainer

The JNDI providers work with almost no special configuration at all. The JPAContainerFactory has factory methods for creating various JNDI provider types. The only thing that you commonly need to do is to expose the EntityManager to a JNDI address. By default, the JNDI providers look for the EntityManager from "java:comp/env/persistence/em". This can be done with the following snippet in web.xml or with similar configuration with annotations.

<persistence-context-ref> <persistence-context-ref-name>

persistence/em </persistence-context-ref-name>

<persistence-unit-name>MYPU</persistence-unit-name> </persistence-context-ref>

The "MYPU" is the identifier of your persistence unit defined in your persistence.xml file.

If you choose to annotate your servlets (instead of using the web.xml file as described above), you can simply add the following annotation to your servlet.

@PersistenceContext(name="persistence/em",unitName="MYPU")

If you wish to use another address for the persistence context, you can define them with the setJndiAddresses() method.You can also define the location for the JTA UserTransaction, but that should be always accessible from "java:comp/UserTransaction" by the JEE6 specification.

21.5.3. Entity Providers as Enterprise Beans

Entity providers can be Enterprise JavaBeans (EJB). This may be useful if you use JPAContainer in a Java EE application server. In such case, you need to implement a custom entity provider that allows the server to inject the entity manager.

For example, if you need to use Java Transaction API (JTA) for JPA transactions, you can implement such entity provider as follows. Just extend a built-in entity provider of your choise and annotate the entity manager member as @PersistenceContext. Entity providers can be either stateless or stateful session beans. If you extend a caching entity provider, it has to be stateful.

@Stateless

@TransactionManagement

public class MyEntityProviderBean extends MutableLocalEntityProvider<MyEntity> {

@PersistenceContext private EntityManager em;

protected LocalEntityProviderBean() { super(MyEntity.class); setTransactionsHandledByProvider(false);

}

@Override

@TransactionAttribute(TransactionAttributeType.REQUIRED) protected void runInTransaction(Runnable operation) {

super.runInTransaction(operation);

}

@PostConstruct public void init() {

setEntityManager(em);

/*

*The entity manager is transaction-scoped, which means

*that the entities will be automatically detached when

*the transaction is closed. Therefore, we do not need

468

Entity Providers as Enterprise Beans



Vaadin JPAContainer

* to explicitly detach them. */

setEntitiesDetached(false);

}

}

If you have more than one EJB provider, you might want to create an abstract super class of the above and only define the entity type in implementations. You can implement an entity provider as a managed bean in Spring Framefork the same way.

21.6. Filtering JPAContainer

Normally, a JPAContainer contains all instances of a particular entity type in the persistence context. Hence, it is equivalent to a database table or query. Just like with database queries, you often want to narrow the results down. JPAContainer implements the Filterable interface in Vaadin containers, described in Section 9.5.7, “Filterable Containers”. All filtering is done at the database level with queries, not in the container.

For example, let us filter all the people older than 117:

Filter filter = new Compare.Greater("age", 117); persons.addContainerFilter(filter);

This would create a JPQL query somewhat as follows:

SELECT id FROM Person WHERE (AGE > 117)

The filtering implementation uses the JPA 2.0 Criteria API transparently. As the filtering is done at the database-level, custom filters that use the Filterable API do not work.

When using Hibernate, note that it does not support implicit joins. See Section 21.9.3, “Joins in Hibernate vs EclipseLink” for more details.

21.7. Querying with the Criteria API

When the Filterable API is not enough and you need to have more control, you can make queries directly with the JPA Criteria API. You may also need to customize sorting or joins, or otherwise modify the query in some way. To do so, you need to implement a QueryModifierDelegate that the JPAContainer entity provider calls when making a query. The easiest way to do this is to extend DefaultQueryModifierDelegate, which has empty implementations of all the methods so that you can only override the ones you need.

The entity provider calls specific QueryModifierDelegate methods at different stages while making a query. The stages are:

1.Start building a query

2.Add "ORDER BY" expression

3.Add "WHERE" expression (filter)

4.Finish building a query

Filtering JPAContainer

469


Vaadin JPAContainer

Methods where you can modify the query are called before and after each stage as listed in the following table:

Table 21.2. QueryModifierDelegate Methods

queryWillBeBuilt()

orderByWillBeAdded()

orderByWasAdded()

filtersWillBeAdded()

filtersWereAdded() queryHasBeenBuilt()

All the methods get two parameters. The CriteriaBuilder is a builder that you can use to build queries. The CriteriaQuery is the query being built.

You can use the getRoots().iterator().next() in CriteriaQuery to get the "root" that is queried, for example, the PERSON table, etc.

21.7.1. Filtering the Query

Let us consider a case where we modify the query for a Person container so that it includes only people over 116. This trivial example is identical to the one given earlier using the Filterable interface.

persons.getEntityProvider().setQueryModifierDelegate( new DefaultQueryModifierDelegate () {

@Override

public void filtersWillBeAdded( CriteriaBuilder criteriaBuilder, CriteriaQuery<?> query, List<Predicate> predicates) {

Root<?> fromPerson = query.getRoots().iterator().next();

// Add a "WHERE age > 116" expression Path<Integer> age = fromPerson.<Integer>get("age"); predicates.add(criteriaBuilder.gt(age, 116));

}

});

21.7.2. Compatibility

When building queries, you should consider the capabilities of the different JPA implementations. Regarding Hibernate, see Section 21.9.3, “Joins in Hibernate vs EclipseLink”.

21.8. Automatic Form Generation

The JPAContainer FieldFactory is an implementation of the FormFieldFactory and TableFieldFactory interfaces that can generate fields based on JPA annotations in a POJO. It goes further than the DefaultFieldFactory, which only creates simple fields for the basic data types. This way, you can easily create forms to input entities or enable editing in tables.

470

Filtering the Query

Vaadin JPAContainer

The generated defaults are as follows:

 

Annotation

Class Mapping

@ManyToOne

NativeSelect

@OneToOne, @Embedded

Nested Form

@OneToMany, @ElementCollection

MasterDetailEditor (see below)

@ManyToMany

Selectable Table

The field factory is recusive, so that you can edit a complex object tree with one form.

21.8.1. Configuring the Field Factory

The FieldFactory is highly configurable with various configuration settings and by extending.

The setMultiSelectType() and setSingleSelectType() allow you to specify a selection component that is used instead of the default for a field with @ManyToMany and @ManyToOne annotation, respectively. The first parameter is the class type of the field, and the second parameter is the class type of a selection component. It must be a sub-class of AbstractSelect.

The setVisibleProperties() controls which properties (fields) are visible in generated forms, subforms, and tables. The first paramater is the class type for which the setting should be made, followed by the IDs of the visible properties.

The configuration should be done before binding the form to a data source as that is when the field generation is done.

Further configuration must be done by extending the many protected methods. Please see the API documentation for the complete list.

21.8.2. Using the Field Factory

The most basic use case for the JPAContainer FieldFactory is with a Form bound to a container item:

// Have a persistent container

final JPAContainer<Country> countries = JPAContainerFactory.make(Country.class, "book-examples");

// For selecting an item to edit

final Select countrySelect = new Select("Select a Country", countries);

countrySelect.setItemCaptionMode(Select.ITEM_CAPTION_MODE_PROPERTY); countrySelect.setItemCaptionPropertyId("name");

// Country Editor

final Form countryForm = new Form(); countryForm.setCaption("Country Editor"); countryForm.addStyleName("bordered"); // Custom style countryForm.setWidth("420px"); countryForm.setWriteThrough(false); // Enable buffering countryForm.setEnabled(false);

// When an item is selected from the list...

countrySelect.addListener(new ValueChangeListener() { @Override

public void valueChange(ValueChangeEvent event) { // Get the item to edit in the form

Item countryItem =

Configuring the Field Factory

471


Vaadin JPAContainer

countries.getItem(event.getProperty().getValue());

//Use a JPAContainer field factory

//- no configuration is needed here

final FieldFactory fieldFactory = new FieldFactory(); countryForm.setFormFieldFactory(fieldFactory);

//Edit the item in the form countryForm.setItemDataSource(countryItem); countryForm.setEnabled(true);

//Handle saves on the form

final Button save = new Button("Save"); countryForm.getFooter().removeAllComponents(); countryForm.getFooter().addComponent(save); save.addListener(new ClickListener() {

@Override

public void buttonClick(ClickEvent event) { try {

countryForm.commit();

countryForm.setEnabled(false); } catch (InvalidValueException e) {

}

}

});

}

});

countrySelect.setImmediate(true);

countrySelect.setNullSelectionAllowed(false);

This would create a form shown in Figure 21.6, “Using FieldFactory with One-to-Many Relationship”.

Figure 21.6. Using FieldFactory with One-to-Many Relationship

If you use Hibernate, you also need to pass an EntityManagerPerRequestHelper, either for the constructor or with setEntityManagerPerRequestHelper(), as described in Section 21.9.2, “The EntityManager-Per-Request pattern”.

472

Using the Field Factory