JPA refreshing inverse fields in a transactionally consistent manner - jpa-2.0

This has bugged me for years but I cannot find anything about it in jpa references nor this site. When an entity has a computed member (Inverse via mappedby, #Formula, ...), there doesn't seem to be any way to get a transactionally consistent update of that computed member. The pattern seems to be that the setter of the one side needs to know about the consumers and update them in situ. I must be missing something. Hopefully the below is illustrative enough.
I wouldn't mind if the requirement was that I had to call em.getReference or .find again on the obj w/ the computed members just in case the ones from the original fetch are out of sync, but that just returns the exact same instance w/ no updates of the fields.
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.PersistenceContext;
import org.springframework.transaction.annotation.Transactional;
#Entity
public class InverseProblemDto {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#OneToMany(mappedBy="problem")
public Set<OwnerDto> owners;
public int otherField = 0;
}
#Entity
public class OwnerDto {
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
#ManyToOne
public InverseProblemDto problem;
public int yetAnotherField = 0;
}
#Transactional
public void wontWork(int dbId) {
#PersistenceContext
EntityManager em;
InverseProblemDto probDto = em.find(InverseProblemDto.class, dbId);
probDto.otherField++;
for (OwnerDto other : probDto.owners) {
// do something
}
OwnerDto newOwner = new OwnerDto();
newOwner.problem = probDto;
em.persist(newOwner);
// do more
// How to ensure this finds newOwner w/o breaking transactional integrity by forcing a flush and refresh???
for (OwnerDto other : probDto.owners) {
if (other.id == newOwner.id) System.out.println("Yeah! found it");
}
}

Flush and refresh do not commit the transaction but only issue the pending sql to the database.
You could always change the value yourself like this :
#Entity
public class InverseProblemDto {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#OneToMany(mappedBy="problem")
public Set<OwnerDto> owners;
public int otherField = 0;
public void addOwner(OwnerDto owner) {
...
}
}
#Entity
public class OwnerDto {
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
#ManyToOne
public InverseProblemDto problem;
public int yetAnotherField = 0;
public void setProblem(InverseProblemDto problem) {
if(problem != null) {
problem.addOwners(this);
}
this.problem = problem;
}
}

Related

spring neo4j optional orElse() error

I´m using the example from spring-boot-neo4j , the class ProductServiceImpl on line 37, has a orElse() method.
public Product getById(Long id) {
return productRepository.findById(id).orElse(null);
}
In my case I don´t know why it is marked as error saying that "Cannot resolve method orElse(null),
why so? what am I missing?
This is my Product domain
#NodeEntity
public class Product {
#GraphId
private Long id;
private String description;
private BigDecimal price;
private String imageUrl;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
//getters and setters
}
My repository
import guru.springframework.domain.Product;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.neo4j.repository.Neo4jRepository;
public interface ProductRepository extends GraphRepository<Product> {
Product findById(Long id);
Product deleteById(Long id);
}
Service
import guru.springframework.commands.ProductForm;
import guru.springframework.converters.ProductFormToProduct;
import guru.springframework.domain.Product;
import guru.springframework.repositories.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class ProductServiceImpl implements ProductService {
private ProductRepository productRepository;
private ProductFormToProduct productFormToProduct;
#Autowired
public ProductServiceImpl(ProductRepository productRepository, ProductFormToProduct productFormToProduct) {
this.productRepository = productRepository;
this.productFormToProduct = productFormToProduct;
}
//some methods..
#Override
public Product getById(Long id) {
return productRepository.findById(id).orElse(null);
//return productRepository.findById(id);
}
}
The pom file is the same as pom.xml

Validation of the application resource model has failed during application initialization

I'm trying to create a simple get request using jersey
but got exception
can someone tell me where I got it wrong?
The excption is - "Caused by: org.glassfish.jersey.server.model.ModelValidationException: Validation of the application resource model has failed during application initialization.
"
VersionResource.java
#Path("/versions")
public class VersionResource extends BaseResource<VersionDao, VersionTable>
{
public VersionResource(VersionDao objectDao)
{
super(objectDao);
}
#Override
#Path("/getAppVersions")
#GET
#UnitOfWork
public String getAllRecords(#Context HttpServletRequest req, #QueryParam("callback") String callback) throws JsonProcessingException
{
return super.getAllRecords(req, callback);
}
}
VersionTable.java
#Entity(name = "Versions")
#Table(name = "Versions")
#NamedQueries({ #NamedQuery(name = QueryNames.QUERY_VERSION_GET_ALL, query = "select c from Versions c"), })
public class VersionTable extends baseDataBase implements Serializable
{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "VersionId")
private short versionId;
#Column(name = "VersionPlatform")
#JsonProperty
#NotEmpty
private String versionPlatform;
#Column(name = "VersionNumber")
#JsonProperty
#NotEmpty
private String versionNumber;
#Column(name = "VersionDescription")
#JsonProperty
#NotEmpty
private String versionDescription;
public short getVersionId()
{
return versionId;
}
public void setVersionId(short versionId)
{
this.versionId = versionId;
}
public String VersionPlatformEnum()
{
return versionPlatform;
}
public void setVersionPlatform(String versionPlatform)
{
this.versionPlatform = versionPlatform;
}
public String getVersionNumber()
{
return versionNumber;
}
public void setVersionNumber(String versionNumber)
{
this.versionNumber = versionNumber;
}
public String getVersionDescription()
{
return versionDescription;
}
public void setVersionDescription(String versionDescription)
{
this.versionDescription = versionDescription;
}
}
VersionDao.java
public class VersionDao extends baseAbstractDao<VersionTable> implements IDatabaseActions<VersionTable>
{
public VersionDao(SessionFactory sessionFactory)
{
super(sessionFactory);
}
#Override
public ObjectDaoResponse getAllTableRecords() throws JsonProcessingException
{
List<VersionTable> list = list(namedQuery(QueryNames.QUERY_VERSION_GET_ALL));
return ObjectDaoResponse.getAnOkResponse(list);
}
}
I think you need a no arg constructor for your VersionResource class, but if you really need an argument the value should be passed by injection (see: https://eclipse-ee4j.github.io/jersey.github.io/documentation/latest/jaxrs-resources.html#d0e2692)

A message body writer for Java type was not found

I am receiving following exception:
ClientHandlerException: A message body writer for Java type,
class com.company.testing.repo.model.Privilege,
and MIME media type,
application/octet-stream, was not found
Privilege is an ENUM class:
public enum Privilege {
READ,
WRITE;
}
Resource entry is this:
#Path("repoPrivs")
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
Response getGroups(Privilege privilege);
my client code is this:
#Override
public List<MyGroup> getGroups(Privilege privilege) {
IWebParamaterProvider provider = WebParamaterFactory.create("repo-mapping/repoPrivs", //$NON-NLS-1$
SecureAction.READ, webProxy);
provider = provider.setType(MediaType.APPLICATION_JSON);
provider = provider.setAccept(MediaType.APPLICATION_JSON);
List<MyGroup> groups = null;
groups = webProxy.post(provider, new GenericTypeFactory<MyGroup>(), MyGroup.class, privilege);
return groups;
}
Override
public final <T> List<T> post(IWebParamaterProvider provider, GenericTypeFactory<T> genericsFactory,
Class<T> clazz, Object requestEntity){
WebResource resource = ((IWebResourceProvider) provider).getWebResource();
TRACER.trace("POST: " + resource.getURI().toString()); //$NON-NLS-1$
return resource.post(genericsFactory.create(clazz), requestEntity);
}
public GenericType<List<T>> create(final Class<T> clazz) {
ParameterizedType genericType = new ParameterizedType() {
#Override
public Type[] getActualTypeArguments() {
return new Type[] { clazz };
}
#Override
public Type getOwnerType() {
return List.class;
}
#Override
public Type getRawType() {
return List.class;
}
};
return new GenericType<List<T>>(genericType) {
};
}
What is that I am missing
It is very important to provide complete minimal example so other people can help you.
Below you have Jersey 2 and Jersey 1 example and both of them uses in memory test container. Make sure to get the all the required dependencies based on the version.
Jersey 2
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.inmemory.InMemoryTestContainerFactory;
import org.glassfish.jersey.test.spi.TestContainerFactory;
import org.junit.Test;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.junit.Assert.*;
public class JerseyVersion2Test extends JerseyTest {
#Path("hello")
public static class HelloResource {
#POST
#Produces(APPLICATION_JSON)
#Consumes(APPLICATION_JSON)
public List<MyGroup> doPost(Privilege privilege) {
List<MyGroup> myGroups = new ArrayList<>();
MyGroup myGroup = new MyGroup();
myGroup.name = "jersey";
myGroup.version = 2;
myGroups.add(myGroup);
return myGroups;
}
}
#Override
protected Application configure() {
return new ResourceConfig(HelloResource.class);
}
#Override
protected TestContainerFactory getTestContainerFactory() {
return new InMemoryTestContainerFactory();
}
#Test
public void testPost() {
List<MyGroup> myGroups = getGroups();
assertEquals(1, myGroups.size());
}
public enum Privilege {
READ,
WRITE;
}
public List<MyGroup> getGroups() {
List<MyGroup> groups = target("hello").request().
accept(MediaType.APPLICATION_JSON).
post(Entity.json(Privilege.READ)).
readEntity(new GenericTypeFactory<MyGroup>().create(MyGroup.class));
return groups;
}
#JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public static class MyGroup {
private String name;
private double version;
}
public class GenericTypeFactory<T> {
public GenericType<List<T>> create(final Class<T> clazz) {
ParameterizedType genericType = new ParameterizedType() {
#Override
public Type[] getActualTypeArguments() {
return new Type[]{clazz};
}
#Override
public Type getOwnerType() {
return List.class;
}
#Override
public Type getRawType() {
return List.class;
}
};
return new GenericType<List<T>>(genericType) {
};
}
}
}
Jersey 1
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.test.framework.AppDescriptor;
import com.sun.jersey.test.framework.JerseyTest;
import com.sun.jersey.test.framework.LowLevelAppDescriptor;
import com.sun.jersey.test.framework.spi.container.TestContainerFactory;
import com.sun.jersey.test.framework.spi.container.inmemory.InMemoryTestContainerFactory;
import org.junit.Test;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.junit.Assert.assertEquals;
public class JerseyVersion1Test extends JerseyTest {
#Path("hello")
public static class HelloResource {
#POST
#Produces(APPLICATION_JSON)
#Consumes(APPLICATION_JSON)
public List<MyGroup> doPost(Privilege privilege) {
List<MyGroup> myGroups = new ArrayList<>();
MyGroup myGroup = new MyGroup();
myGroup.name = "jersey";
myGroup.version = 1.12;
myGroups.add(myGroup);
return myGroups;
}
}
#Override
protected AppDescriptor configure() {
return new LowLevelAppDescriptor.Builder(HelloResource.class).build();
}
#Override
protected TestContainerFactory getTestContainerFactory() {
return new InMemoryTestContainerFactory();
}
#Test
public void testPost() {
List<MyGroup> myGroups = getGroups();
assertEquals(1, myGroups.size());
}
public enum Privilege {
READ,
WRITE;
}
public List<MyGroup> getGroups() {
WebResource webResource = resource();
List<MyGroup> groups = webResource.path("hello").
accept(MediaType.APPLICATION_JSON).
type(MediaType.APPLICATION_JSON).
post(new GenericTypeFactory<MyGroup>().create(MyGroup.class), Privilege.READ);
return groups;
}
#JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public static class MyGroup {
private String name;
private double version;
}
public class GenericTypeFactory<T> {
public GenericType<List<T>> create(final Class<T> clazz) {
ParameterizedType genericType = new ParameterizedType() {
#Override
public Type[] getActualTypeArguments() {
return new Type[]{clazz};
}
#Override
public Type getOwnerType() {
return List.class;
}
#Override
public Type getRawType() {
return List.class;
}
};
return new GenericType<List<T>>(genericType) {
};
}
}
}
javax.xml.bind.annotation.XmlRootElement
Java doc:
The #XmlRootElement annotation can be used with the following program
elements:
a top level class
an enum type
[...]
When a top level class or an enum type is annotated with the #XmlRootElement annotation, then its value is represented as XML element in an XML document.
in your case it is clear that Jersey unable to unmarshall the incoming JSON payload to your object, thus the exception
A message body writer for Java type, class com.company.testing.repo.model.Privilege
annotating your Enum (Privilege) with #XmlRootElement should solve the issue.
#XmlRootElement
public enum Privilege {
READ,
WRITE;
}

Lazy loading in TomEE is not working as expected

Entity's lazy property is always returning null value in TomEE, but working in Glassfish 3 as expected. Is there any listener i am missing to include in web.xml or something else? How to fetch lazy property?
Here is the source code:
AppGroup.java:
package uz.mf.javaee6app;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
#Entity
public class AppGroup implements Serializable {
#Id
#GeneratedValue
private Long id;
private String name;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
AppUser.java:
package uz.mf.javaee6app;
import java.io.Serializable;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
*
* #author ravshan
*/
#Entity
public class AppUser implements Serializable {
#Id
#GeneratedValue
private Long id;
private String name;
private List<AppGroup> roles;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public List<AppGroup> getRoles() { return roles; }
public void setRoles(List<AppGroup> roles) { this.roles = roles; }
}
I'm skipping AppUserFacade stateless bean and UserManager CDI bean, there's nothing special. and the last users.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
Selected user: #{userManager.selectedUser.name}
<h:dataTable value="#{userManager.selectedUser.roles}" var="role">
<h:column>#{role.name}</h:column>
</h:dataTable>
</h:body>
</html>
UserManager.java:
package uz.mf.javaee6app;
import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
#Named
#SessionScoped
public class UserManager implements Serializable {
private AppUser selectedUser;
public AppUser getSelectedUser() {
return selectedUser;
}
public void setSelectedUser(AppUser selectedUser) {
this.selectedUser = selectedUser;
}
}
Selected user is being set by another view.
I'd bet the problem is that somehow your Entity is getting detached prior to accessing the lazy loaded field. Be sure to check your transaction attributes to ensure that your context is still active when you are trying to get lazy loading working.

Why can't I instantiate a managedbean in jpa?

I am trying to develop a small web application as training for my upcoming finals and I can't figure out what I'm doing wrong.
These are my *Entities*L Kunde and Konto (many2many-relationship), the auto-created table Kunde_Konto has only the two primary keys of my entities.
#Entity
#NamedQueries({
#NamedQuery(name="findKundeById", query="select k from Kunde k where k.svnr = :svnr"),
})
public class Kunde implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(precision=4, scale=0)
private Long svnr;
#ManyToMany
private List<Konto> konten;
}
#Entity
#NamedQueries({
#NamedQuery(name="findKontoByBesitzer", query="select k from Konto k join k.besitzer b where b.svnr = :svnr")
})
public class Konto implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(precision=4, scale=0)
private Long knr;
#ManyToMany(mappedBy="konten")
private List<Kunde> besitzer;
}
And this is my Managed Bean:
#ManagedBean
#SessionScoped
public class KundenKontoList implements Serializable {
private FacesContext fc = null;
private HttpServletRequest hsr = null;
private HttpSession hs = null;
#EJB
private KontoFacadeLocal kontoFacade;
#EJB
private KundeFacadeLocal kundeFacade;
private Kunde k;
private List<Konto> konten;
/**
* Creates a new instance of KundenKontoList
*/
public KundenKontoList() {
fc = FacesContext.getCurrentInstance();
hsr = (HttpServletRequest) fc.getExternalContext().getRequest();
hs = hsr.getSession();
k = (Kunde) hs.getAttribute("kunde");
konten = kontoFacade.findKontoByBesitzer(k);
}
}
The exception
com.sun.faces.mgbean.ManagedBeanCreationException: Klasse at.pf.controller.KundenKontoList kann nicht instanziiert werden.
which translated means that KundenKontoList can't be instatiated, is thrown at the line:
konten = kontoFacade.findKontoByBesitzer(k);
//method in the facade:
#Override
public List<Konto> findKontoByBesitzer(Kunde k) {
Query q = em.createNamedQuery("findKontoByBesitzer");
q.setParameter("svnr", k.getSvnr());
return q.getResultList();
}
I think that it has something to do with the kontoFacade, but I don't know what the exact problem is.
Fail on init of managedbean, suggests to me that injection of ejbs is failing. Is there a longer error message?