I have a problem with resolving entities during entity manager startup.
Now it falls with following error:
Exception [EclipseLink-197] (Eclipse Persistence Services -
2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DescriptorException Exception
Description: The mapping [an_div] is not the appropriate type for this
descriptor Mapping:
org.eclipse.persistence.mappings.DirectToFieldMapping[an_div-->div]
Descriptor:
EISDescriptor(com.cloudyle.paasplus.api.fhir.model.dstu2.composite.NarrativeDt
--> [DatabaseTable(DATATYPE), DatabaseTable(NARRATIVEDT)])
The abstract class configuration:
#MappedSuperclass
#UuidGenerator(name = "UUID_GEN_SQL")
#NoSql(dataFormat = DataFormatType.MAPPED)
public abstract class AbstractBaseResource
{
private static final long serialVersionUID = -1212459053211153257L;
protected static final Logger logger = LoggerFactory.getLogger(AbstractBaseResource.class);
public static final String DELIMITER = ", ";
#Id
#GeneratedValue(generator = "UUID_GEN_SQL")
#Column(name = "_id")
private String id;
#Version
#Field(name = "object_version")
private Long objectVersion;
#Embedded
#Field(name = "text")
private NarrativeDt text;
// getter and setter
// ...
}
A simple entity class:
#Entity
#NoSql(dataFormat = DataFormatType.MAPPED)
public class Account extends AbstractBaseResource
{
#Field(name = "name")
private String an_name;
// other fields + getter and setter
// ...
}
The embbedable entity where the problem could be:
#Embeddable
#NoSql(dataFormat = DataFormatType.MAPPED)
#Customizer(DtChildCustomizer.class)
public class NarrativeDt extends Datatype
{
#Field(name = "status")
private String an_status;
#Field(name = "div")
private String an_div;
// getter and setter
// ...
}
The extended embbedable:
#Embeddable
#NoSql(dataFormat = DataFormatType.MAPPED)
#Customizer(DtParentCustomizer.class)
public abstract class Datatype implements IDatatype, Serializable
{
#Field(name = "element_specific_id")
private String an_elementSpecificId;
// getter and setter
// ...
}
The child customizer:
public class DtChildCustomizer implements Serializable, DescriptorCustomizer
{
#Override
public void customize(final ClassDescriptor descriptor)
{
descriptor.getInheritancePolicy().setParentClass(Datatype.class);
}
}
And the parent customizer:
public class DtParentCustomizer implements Serializable, DescriptorCustomizer
{
#Override
public void customize(final ClassDescriptor descriptor) throws Exception
{
descriptor.getInheritancePolicy().setSingleTableStrategy();
final DatabaseField indicatorField = new DatabaseField();
indicatorField.setName("classType");
indicatorField.setLength(255);
indicatorField.setType(java.lang.String.class);
descriptor.getInheritancePolicy().setClassIndicatorField(indicatorField);
descriptor.getInheritancePolicy().useClassNameAsIndicator();
}
}
I can not understand why eclispeLink have a problem to resolve simple mapping an_div->div.
All suggestion will be appreciated, I already spent too much time working on it. I can not see the mapping problem :(
Kind regards
Related
I would like to show data from two different objects in one Grid. I have "folders" and "items" and I would like to see them together in one Grid. Folders at the top and items below folders. Something like list view in file manager application. But I don't know how to get the data together. I could probably create an abstract parent class for Item and Folder classes with getter methods, which I'm using in the grid. Is there any better solution for that?
Expected result:
#Route(value = "")
#PageTitle("Items | Test")
public class ListView extends VerticalLayout {
Grid<Item> grid = new Grid<>(Item.class);
ItemService service;
Folder currentFolder;
public ListView(ItemService service) {
this.service = service;
this.currentFolder = service.getAllFolders().get(0);
addClassName("list-view");
add(getGrid());
updateList();
}
private HorizontalLayout getGrid() {
HorizontalLayout layout = new HorizontalLayout(grid);
layout.setSizeFull();
grid.addClassNames("grid");
grid.setColumns("name");
grid.addColumn(testCase -> testCase.getStatus().getValue()).setHeader("Status").setSortable(true);
grid.addColumn(new ComponentRenderer<>(
testCase -> {
Checkbox checkbox = new Checkbox();
checkbox.setValue(testCase.getBooleanValue());
checkbox.setReadOnly(true);
return checkbox;
}
)
).setHeader("Boolean");
grid.getColumns().forEach(col -> col.setAutoWidth(true));
return layout;
}
private void updateList() {
grid.setItems(service.getItemsFromFolder(currentFolder));
}
}
Service:
#Service
public class ItemService {
private final ItemRepository itemRepository;
private final FolderRepository folderRepository;
public ItemService(ItemRepository itemRepository, FolderRepository folderRepository) {
this.itemRepository = itemRepository;
this.folderRepository = folderRepository;
}
public List<Folder> getAllFolders() {
return folderRepository.findAll();
}
public List<Item> getItemsFromFolder(Folder folder) {
return itemRepository.getItemsFromFolder(folder.getId());
}
}
Item Repository:
public interface ItemRepository extends JpaRepository<Item, Long> {
#Query("Select i from Item i where i.folder.id = :folderId")
List<Item> getItemsFromFolder(#Param("folderId") Long folderId);
}
Folder Repository:
public interface FolderRepository extends JpaRepository<Folder, Long> {
}
Item Entity:
#Entity
#Getter
#Setter
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotEmpty
private String name = "";
#Enumerated
#Column(columnDefinition = "smallint")
private Status status;
#NotNull
private Boolean booleanValue;
#ManyToOne
#JoinColumn(name = "folder_id")
#NotNull
private Folder folder;
}
Folder Entity:
#Entity
#Getter
#Setter
public class Folder {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Long parentFolderId;
}
Status enum:
#AllArgsConstructor
public enum Status {
DRAFT("Draft"),
READY("Ready"),
OBSOLETE("Obsolete");
#Getter
private final String value;
}
Grid can only have one type of bean, so an abstract parent class or interface is the way to go. But given the description of your use case of "folders" and "items", have you considered using TreeGrid instead?
I have an ExampleRequest entity that can optionally have one or more ExampleRequestYear. It's currently configured this way (unrelated fields and gettters/setters omitted for brevity, please let me know if you need anything else):
#Entity
#Table(name = "EXAMPLE_REQUEST")
#SequenceGenerator(name = "EXAMPLE_REQUEST_ID_SEQ", sequenceName = "EXAMPLE_REQUEST_ID_SEQ", allocationSize = 1)
#Cacheable(false)
public class ExampleRequest implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "EXAMPLE_REQUEST_ID_SEQ")
#Column(name="EXAMPLE_REQUEST_ID", nullable = false)
private Long exampleRequestId;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "exampleRequest")
private List<ExampleRequestYear> exampleRequestYearList;
public ExampleRequest() {
}
public List<ExampleRequestYear> getExampleRequestYearList() {
if(this.exampleRequestYearList == null){
this.exampleRequestYearList = new ArrayList<ExampleRequestYear>();
}
return this.exampleRequestYearList;
}
public void setExampleRequestYearList(List<ExampleRequestYear> exampleRequestYearList) {
this.exampleRequestYearList = exampleRequestYearList;
}
public ExampleRequestYear addExampleRequestYear(ExampleRequestYear exampleRequestYear) {
getExampleRequestYearList().add(exampleRequestYear);
exampleRequestYear.setExampleRequest(this);
return exampleRequestYear;
}
public ExampleRequestYear removeExampleRequestYear(ExampleRequestYear exampleRequestYear) {
getExampleRequestYearList().remove(exampleRequestYear);
exampleRequestYear.setExampleRequest(null);
return exampleRequestYear;
}
}
#Entity
#Table(name = "EXAMPLE_REQUEST_YEAR")
#IdClass(ExampleRequestYearPK.class)
public class ExampleRequestYear implements Serializable {
#Id
#Column(nullable = false)
private Integer year;
#Id
#ManyToOne
#JoinColumn(name = "EXAMPLE_REQUEST_ID", referencedColumnName = "EXAMPLE_REQUEST_ID")
private ExampleRequest exampleRequest;
public ExampleRequestYear() {
}
public void setExampleRequest(ExampleRequest exampleRequest) {
this.exampleRequest = exampleRequest;
}
public ExampleRequest getExampleRequest() {
return exampleRequest;
}
}
Part of the code was auto-generated by the IDE and I'm still wrapping my head around JPA so there're probably design mistakes all around.
My app works (apparently) when I create a new ExampleRequest:
ExampleRequest exampleRequest = new ExampleRequest();
ExampleRequestYear exampleRequestYear = new ExampleRequestYear(2020);
request.addExampleRequestYear(exampleRequestYear);
However, I can't figure out how to edit an existing ExampleRequest because I'm unsure on how I'm meant to retrieve the linked entities. According to articles I've read, lazy fetching should be automatic, yet when I try this:
ExampleRequest exampleRequest = employeeRequestsController.getExampleRequestById(123);
System.out.println(exampleRequest.getExampleRequestYearList().size());
... I get a null pointer exception upon .size() because the getter runs but neither initialises an empty list, nor retrieves items from DB:
public List<ExampleRequestYear> getExampleRequestYearList() {
if(this.exampleRequestYearList == null){
// Field is null and conditional is entered
this.exampleRequestYearList = new ArrayList<ExampleRequestYear>();
// After initialisation, field is still null!
}
return this.exampleRequestYearList;
}
Also, switch to FetchType.EAGER solves this particular problem entirely. What am I missing?
Further details regarding app design. The Resource classes that handle HTTP requests interact with a set of Controller classes like this:
#Stateless(name = "ISomeActionController", mappedName = "ISomeActionController")
public class SomeActionController implements ISomeActionController {
#EJB
private IFooDAO fooDao;
#EJB
private IBarDAO barDao;
#Override
public ExampleRequest getExampleRequestById(Long exampleRequestId) {
return fooDao.getEntityById(exampleRequestId);
}
}
It's in the DAO classes where EntityManager is injected an used:
#Local
public interface IGenericDAO<T> {
public T persistEntity(T o);
public T persistEntityCommit(T o);
public void removeEntity(T o);
public void removeEntity(long id);
public T mergeEntity(T o);
public List<T> getEntitiesFindAll();
public List<T> getEntitiesFindAllActive();
public T getEntityById(Object id);
}
public interface IFooDAO extends IGenericDAO<ExampleRequest> {
public void flushDAO();
public ExampleRequest getExampleRequestById(Long exampleRequestId);
}
#Stateless(name = "IFooDAO", mappedName = "IFooDAO")
public class FooDAO extends GenericDAO<ExampleRequest> implements IFooDAO {
public FooDAO() {
super(ExampleRequest.class);
}
#Override
public void flushDAO(){
em.flush();
}
#Override
public ExampleRequest getExampleRequestById(Long exampleRequestId){
String sql = "...";
Query query = em.createNativeQuery(sql, ExampleRequest.class);
//...
}
}
I am using jackson-dataformat-xml.
I have the following classes:
public class CTHotel {
#JacksonXmlProperty(localName = "basic-info")
private HotelBaseInfo hotelBaseInfo;
//other properties and getters and setters
}
public class HotelBaseInfo {
#JacksonXmlProperty(localName = "hotel-name")
private String hotelName;
#JacksonXmlElementWrapper(localName = "hotel-amenities")
private List<HotelAmenity> hotelAmenities;
//other properties and getters/setters
}
public class HotelAmenity {
private String category;
private String description;
#JacksonXmlElementWrapper(localName = "amenities")
private List<String> amenities;
//other properties and getters/setters
}
My XML is this:
<hotels>
<hotel>
<basic-info>
<hotel-name>Hotel XYZ</hotel-name>
<hotel-amenities>
<hotel-amenity>
<category>F&B</category>
<description>Random Text</description>
<amenities>
<amenity>Cafe</amenity>
<amenity>Bar</amenity>
<amenity>Rastaurant</amenity>
</amenities>
</hotel-amenity>
<hotel-amenity>
...
</hotel-amenity>
</hotel-amenities>
</basic-info>
</hotel>
<hotel>
...
</hotel>
</hotels>
My question is, how can I map amenities as list of strings in my HotelAmenity class as mentioned above ? What annotation should I use on amenities field ?
#JacksonXmlElementWrapper annotation on hotelAmenities field of Hotel class is working just fine.
I get the below error while mapping :
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: java.io.StringReader#507bcc81; line: 3, column: 1039] (through reference chain: com.example.response.HotelSearchResponse["hotels"]->java.util.ArrayList[2]->com.example.response.CTHotel["basic-info"]->com.example.response.HotelBaseInfo["hotel-amenities"]->java.util.ArrayList[1]->com.example.response.HotelAmenity["amenities"]->java.util.ArrayList[9])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148) ~[jackson-databind-2.6.5.jar:2.6.5]
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:857) ~[jackson-databind-2.6.5.jar:2.6.5]
...
Here's the code, that I hope would answer your question:
/**Class Hotels*/
#JacksonXmlRootElement(localName = "hotels")
public class Hotels {
#JacksonXmlElementWrapper(useWrapping = false)
private List<Hotel> hotel;
//Other getters and setters
}
/**Class Hotel*/
#JacksonXmlRootElement(localName = "hotel")
public class Hotel {
#JacksonXmlProperty(localName = "basic-info")
private HotelBaseInfo hotelBaseInfo;
//Other getters and setters
}
/**Class HotelBaseInfo*/
public class HotelBaseInfo {
#JacksonXmlProperty(localName = "hotel-name")
private String hotelName;
#JacksonXmlElementWrapper(localName = "hotel-amenities")
private List<HotelAmenity> hotelAmenities;
//Other getters and setters
}
/**Class HotelAmenity*/
public class HotelAmenity {
private String category;
private String description;
#JacksonXmlElementWrapper(localName = "amenities")
private List<Amenities> amenity;
static class Amenities {
#JacksonXmlText
private String value;
}
//Other getters and setters
}
Here's what worked for me:
public class JacksonXmlParsing {
#JacksonXmlRootElement(localName = "hotels")
static class HotelSearchResponse {
#JacksonXmlElementWrapper(localName = "hotel")
private List<CTHotel> hotels;
//other properties and getters and setters
}
static class CTHotel {
#JacksonXmlProperty(localName = "hotel-name")
private String hotelName;
#JacksonXmlElementWrapper(localName = "hotel-amenities")
private List<HotelAmenity> hotelAmenities;
//other properties and getters and setters
}
static class HotelAmenity {
private String category;
private String description;
#JacksonXmlElementWrapper
private List<String> amenities;
//other properties and getters/setters
}
public static void main(String[] args) throws IOException {
XmlMapper xmlMapper = new XmlMapper();
File file = new File("./src/main/resources/file.xml");
HotelSearchResponse response = xmlMapper.readValue(file, HotelSearchResponse.class);
System.out.println(response);
}
}
Output:
HotelSearchResponse(hotels=[CTHotel(hotelName=Hotel XYZ, hotelAmenities=[HotelAmenity(category=F&B, description=Random Text, amenities=[Cafe, Bar, Rastaurant])])])
But basic-info tag is missed, I could find out why.
I generated a form:
<form:form action="${contextPath}/draw/constraints.do" method="post" modelAttribute="order"> <c:forEach items="${order.myDrawsAsArray}" var="draw" varStatus="status">
<label class="radio-inline"><form:radiobutton path="myDrawsAsArray[${status.index}].readable" value="true" /> yes</label>
<label class="radio-inline"><form:radiobutton path="myDrawsAsArray[${status.index}].readable" value="false" /> no</label>
</c:forEach></form:form>
When I submit it to update my entities, I got the following exception:
org.springframework.web.util.NestedServletException: Request
processing failed; nested exception is
org.springframework.beans.InvalidPropertyException: Invalid property
'myDrawsAsArray[0]' of bean class [com.entity.Order3d]: Getter
for property 'myDrawsAsArray' threw exception; nested exception is
java.lang.reflect.InvocationTargetException
org.springframework.beans.InvalidPropertyException: Invalid property
'myDrawsAsArray[0]' of bean class [com.entity.Order3d]: Getter
for property 'myDrawsAsArray' threw exception; nested exception is
java.lang.reflect.InvocationTargetException
java.lang.reflect.InvocationTargetException
java.lang.NullPointerException
com.entity.Order3d.getMyDrawsAsArray(Order3d.java:121)
My controller is like this:
#Controller
#RequestMapping("/draw")
public class PrintingController {
#RequestMapping(value="/constraints")
public String constraints(
#ModelAttribute Order3d order,
#RequestParam("order") int id,
#RequestParam(value="save", required=false) String save,
Model m) {
Session s=HibernateUtils.getSessionFactory().openSession();
if(save!=null) {
System.out.println(order.getMyDraws());
for(DrawFile df : order.getMyDraws())
s.saveOrUpdate(df);
}
Order3d o=(Order3d)s.createCriteria(Order3d.class).add(Restrictions.eq("id", id)).uniqueResult();
m.addAttribute("order", o);
s.close();
return "3dconstraints";
}
}
I also post my entities if you need them:
#Entity
#Table (name="order3d")
public class Order3d implements Serializable {
private static final long serialVersionUID = -2241346447352903470L;
public enum State {DEMAND, ESTIMATED, PAYED, PENDING, PRODUCED, SENT, DELIVERED};
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column (name="id")
private int id;
#OneToMany(mappedBy="order3d", fetch = FetchType.EAGER, cascade=CascadeType.ALL)
private Set<DrawFile> myDraws;
public Set<DrawFile> getMyDraws() {
return myDraws;
}
public List<DrawFile> getMyDrawsAsList() {
return new ArrayList<DrawFile>(myDraws);
}
public Object[] getMyDrawsAsArray() {
return myDraws.toArray(); //line 121
}
//other getters & setters
public Order3d() {}
}
#Entity
#Table (name="draw", uniqueConstraints=#UniqueConstraint(columnNames="hashname"))
public class DrawFile implements Serializable {
private static final long serialVersionUID = -9024754876558087847L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column (name="id")
private int id;
#Column (name="hashname", columnDefinition="CHAR(64)")
private String hashname;
#Column (name="filename")
private String filename="";
#Column (name="readable", columnDefinition = "BIT", length = 1)
private Boolean readable;
//getters & setters
public DrawFile() {}
}
I searched on the web but I didn't find a solution. Any idea?
How about try adding getter/setter to the fields in both Order3d and DrawFile classes?
The getters and setters must match field name, if the field is
List<DrawFile> myDraws;
then the getter/setter must be: (it cannot be getMyDrawsAsList())
public List<DrawFile> getMyDraws() {
return myDraws;
}
public void setMyDraws(List<DrawFile> myDraws) {
this.myDraws = myDraws;
}
In my data model, I have something to this effect:
#Entity
public class Target {
#Id
#GeneratedValue
private Long id;
/* ...etc... */
}
#Entity
public class Dependency {
#Id
#GeneratedValue
private Long id;
#ManyToOne(optional=false)
#Column(name="target_id")
private Target target;
/* ...etc... */
}
I'm already serializing Target just fine, but I need to serialize Dependency. Essentially, what I need is something like this:
<dependency>
<id>100</id>
<targetId>200</targetId>
</dependency>
Is there a way to do this in JAXB annotations without modifying my model?
You could use an XmlAdapter for this use case:
package forum7278406;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class TargetAdapter extends XmlAdapter<Long, Target> {
#Override
public Long marshal(Target target) throws Exception {
return target.getId();
}
#Override
public Target unmarshal(Long id) throws Exception {
Target target = new Target();
target.setId(id);
return target;
}
}
The XmlAdapter is registered on the Dependency class using the #XmlJavaTypeAdapter annotation:
package forum7278406;
import javax.persistence.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#Entity
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Dependency {
#Id
#GeneratedValue
private Long id;
#ManyToOne(optional=false)
#Column(name="target_id")
#XmlJavaTypeAdapter(TargetAdapter.class)
private Target target;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Target getTarget() {
return target;
}
public void setTarget(Target target) {
this.target = target;
}
}
Going Further
Instead of just creating a new instance of Target we could use an EntityManager to query the corresponding instance from the database. Our XmlAdapter would be changed to look something like:
package forum7278406;
import javax.persistence.EntityManager;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class TargetAdapter extends XmlAdapter<Long, Target> {
EntityManager entityManager;
public TargetAdapter() {
}
public TargetAdapter(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Override
public Long marshal(Target target) throws Exception {
return target.getId();
}
#Override
public Target unmarshal(Long id) throws Exception {
Target target = null;
if(null != entityManager) {
target = entityManager.find(Target.class, id);
}
if(null == target) {
target = new Target();
target.setId(id);
}
return target;
}
}
Now to set the instance of EntityManager on our XmlAdapter, we can do the following:
Unmarshaller umarshaller = jaxbContext.createUnmarshaller();
TargetAdapter targetAdatper = new TargetAdapter(entityManager);
unmarshaller.setAdapter(targetAdapter);
It works for EclipseLink MOXy with XmlID and XmlIDRef (but fails for sun JAXB, where XmlID must be string)
#Entity
#XmlRootElement
public class Target {
#Id
#GeneratedValue
#XmlID
#XmlElement
private Long id;
}
#Entity
#XmlRootElement
public class Dependency {
#Id
#GeneratedValue
#XmlElement
private Long id;
#ManyToOne(optional = false)
#Column(name = "target_id")
#XmlIDREF
#XmlElement(name = "targetId")
private Target target;
}