Child object missing in Java Rest webservice - java

i am trying to call the get method of the below web service
#Stateless
#Path("com.company.entitiesms.bom")
public class BomFacadeREST extends AbstractFacade<Bom> {
#PersistenceContext(unitName = "com.mycompany_rxws_war_1.0-SNAPSHOTPU")
private EntityManager em;
public BomFacadeREST() {
super(Bom.class);
}
#GET
#Path("{id}")
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Bom find(#PathParam("id") Long id) {
return super.find(id);
}
where it should get all the xml elements and child elements in the entity class BOM:
#Entity
#Table(catalog = "MOI", schema = "dbo")
#XmlRootElement
public class Bom implements Serializable {
#Id
#Basic(optional = false)
#NotNull
#Column(name = "BOM_ID", nullable = false)
private Long bomId;
#OneToMany(mappedBy = "bomId")
private Collection<BOMDevices> bOMDevicesCollection;
#OneToMany(mappedBy = "bomId")
private Collection<TRInstallations> tRInstallationsCollection;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "bomId")
private Collection<BOMATEs> bOMATEsCollection;
public Bom() {
}
public Bom(Long bomId) {
this.bomId = bomId;
}
public Long getBomId() {
return bomId;
}
public void setBomId(Long bomId) {
this.bomId = bomId;
}
//#XmlTransient
public Collection<BOMATEs> getBOMATEsCollection() {
return bOMATEsCollection;
}
public void setBOMATEsCollection(Collection<BOMATEs> bOMATEsCollection) {
this.bOMATEsCollection = bOMATEsCollection;
}
#XmlTransient
public Collection<BOMDevices> getBOMDevicesCollection() {
return bOMDevicesCollection;
}
public void setBOMDevicesCollection(Collection<BOMDevices>
bOMDevicesCollection) {
this.bOMDevicesCollection = bOMDevicesCollection;
}
the problem is Collection of BOMATEs is not generated in the xml output of the get method in the above web service and its class is as follow:
#Entity
#Table(name = "BOM_ATEs", catalog = "MOI", schema = "dbo")
#XmlRootElement
public class BOMATEs implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#Column(name = "ATE_ID", nullable = false)
private Long ateId;
public BOMATEs() {
}
public BOMATEs(Long ateId) {
this.ateId = ateId;
}
public Long getAteId() {
return ateId;
}
public void setAteId(Long ateId) {
this.ateId = ateId;
}
#XmlTransient
public Collection<BOMDevices> getBOMDevicesCollection() {
return bOMDevicesCollection;
}
public void setBOMDevicesCollection(Collection<BOMDevices>
bOMDevicesCollection) {
this.bOMDevicesCollection = bOMDevicesCollection;
}
public Bom getBomId() {
return bomId;
}
public void setBomId(Bom bomId) {
this.bomId = bomId;
}
}
i tried removing the XmlTransient annotation for the getter getBOMATEsCollection , changing the fetch type to eager with no hope

Related

Problem in updating the entity with unidirectional #ManyToOne relation in SpringBoot application

I have two entities as below and the main problem is when I want to update the AccountRequestStatus entity. I save the integer enum code of AccountRequestStatusEnum in the database to persist the AcountRequest status in the whole application.
AccountRequestStatusEnum
public enum AccountRequestStatusEnum {
INITIAL(0),
SUCCESS(1);
private final Integer type;
AccountRequestStatusEnum(Integer type) {
this.type = type;
}
public Integer getType() {
return type;
}
public static AccountRequestStatusEnum of(Integer type) {
for (AccountRequestStatusEnum accountRequestStatusEnum : AccountRequestStatusEnum.values()) {
if (type.equals(accountRequestStatusEnum.getType()))
return accountRequestStatusEnum;
}
return null;
}
}
AccountRequest
#Entity
#Table(name = "T_ACCOUNT_REQUEST", uniqueConstraints = {#UniqueConstraint(columnNames = {"ACCOUNT_NO", "MESSAGE_ID"})})
#SequenceGenerator(
name = "SEQ_T_ACCOUNT_REQUEST",
sequenceName = "SEQ_T_ACCOUNT_REQUEST",
allocationSize = 1)
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode(callSuper = false)
#ToString
public class AccountRequest extends AbstractAuditingEntity {
private Long id;
private String messageId;
private String issuer;
private EventType type;
private EventName name;
private String accountNo;
private LocalDateTime dateTime;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_T_ACCOUNT_REQUEST")
#Column(name = "ID", nullable = true, insertable = true, updatable = true, precision = 0)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "MESSAGE_ID")
public String getMessageId() {
return messageId;
}
public void setMessageId(String messageId) {
this.messageId = messageId;
}
#Column(name = "ISSUER")
public String getIssuer() {
return issuer;
}
public void setIssuer(String issuer) {
this.issuer = issuer;
}
#Transient
public EventType getType() {
return type;
}
public void setType(EventType type) {
this.type = type;
}
#Column(name = "TYPE")
public Integer getEventTypeCode() {
if (Objects.nonNull(type)) {
return type.getType();
} else return null;
}
public void setEventTypeCode(Integer typeCode) {
type = EventType.of(typeCode);
}
#Transient
public EventName getName() {
return name;
}
public void setName(EventName name) {
this.name = name;
}
#Column(name = "NAME")
public Integer getEventNameCode() {
if (Objects.nonNull(name)) {
return name.getType();
} else return null;
}
public void setEventNameCode(Integer type) {
name = EventName.of(type);
}
#Column(name = "ACCOUNT_NO")
public String getAccountNo() {
return accountNo;
}
public void setAccountNo(String accountNo) {
this.accountNo = accountNo;
}
#Column(name = "DATE_TIME")
public LocalDateTime getDateTime() {
return dateTime;
}
public void setDateTime(LocalDateTime dateTime) {
this.dateTime = dateTime;
}
}
AccountRequestStatus
#Entity
#Table(name = "T_ACCOUNT_REQUEST_STATUS")
#SequenceGenerator(
name = "SEQ_T_ACCOUNT_REQUEST_STATUS",
sequenceName = "SEQ_T_ACCOUNT_REQUEST_STATUS",
allocationSize = 1
)
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class AccountRequestStatus extends AbstractAuditingEntity {
private Long id;
private AccountRequestStatusEnum accountRequestStatusEnum;
private AccountRequest accountRequest;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_T_ACCOUNT_REQUEST_STATUS")
#Column(name = "ID", nullable = true, insertable = true, updatable = true, precision = 0)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Transient
public AccountRequestStatusEnum getAccountRequestStatusEnum() {
return accountRequestStatusEnum;
}
public void setAccountRequestStatusEnum(AccountRequestStatusEnum accountRequestStatusEnum) {
this.accountRequestStatusEnum = accountRequestStatusEnum;
}
#Column(name = "ACCOUNT_REQUEST_STATUS")
public Integer getAccountRequestStatusCode() {
if (Objects.nonNull(accountRequestStatusEnum)) {
return accountRequestStatusEnum.getType();
} else return null;
}
public void setAccountRequestStatusCode(Integer type) {
accountRequestStatusEnum = AccountRequestStatusEnum.of(type);
}
#ManyToOne(targetEntity = AccountRequest.class)
#JoinColumn(name = "ACCOUNT_REQUEST", referencedColumnName = "ID")
public AccountRequest getAccountRequest() {
return accountRequest;
}
public void setAccountRequest(AccountRequest accountRequest) {
this.accountRequest = accountRequest;
}
}
The first time that an account request comes from MQ my to application, I save the initial code of AccountRequestStatusEnum in service like below. This status persists properly and there is no problem, but when I want to update the AccountRequestStatus and add a new success code of AccountRequestStatusEnum (in another service) it won't be saved in DB.
This is the first service that is called after receiving the account request and saving the initial code.
#Service
#Transactional(readOnly = true)
public class AccountRequestServiceImpl implements IAccountRequestService {
#Value("${mq.event_argument_key}")
private String eventArgumentKey;
private final AccountRequestRepository accountRequestRepository;
private final AccountRequestStatusServiceImpl mqRequestStatusService;
private final EventToAccountRequestEntityMapper eventMapper;
private final AccountRequestMapper accountRequestMapper;
#Autowired
public AccountRequestServiceImpl(AccountRequestRepository accountRequestRepository,
AccountRequestStatusServiceImpl mqRequestStatusService,
EventToAccountRequestEntityMapper eventMapper,
AccountRequestMapper accountRequestMapper) {
this.accountRequestRepository = accountRequestRepository;
this.mqRequestStatusService = mqRequestStatusService;
this.eventMapper = eventMapper;
this.accountRequestMapper = accountRequestMapper;
}
#Override
#Transactional(propagation = Propagation.REQUIRES_NEW)// to prevent rollback for whole receive method in mq service
public void saveAccountRequest(Event event) {
AccountRequest accountRequest = eventMapper.eventToAccountRequest(event, eventArgumentKey);
accountRequestRepository.save(accountRequest);
AccountRequestDto accountRequestDto = accountRequestMapper.toDto(accountRequest);
saveAccountRequestStatus(accountRequestDto, AccountRequestStatusEnum.INITIAL);
}
private void saveAccountRequestStatus(AccountRequestDto accountRequestDto, AccountRequestStatusEnum status) {
AccountRequestStatusDto accountRequestStatusDto = new AccountRequestStatusDto();
accountRequestStatusDto.setAccountRequestStatusEnum(status);
accountRequestStatusDto.setAccountRequestDto(accountRequestDto);
mqRequestStatusService.saveAccountRequestStatus(accountRequestStatusDto);
}
}
This is the second service that should save the success code of AccountRequestStatus.
#Service
#Transactional(readOnly = true)
public class SyncLegacyAccountServiceImpl implements ISyncLegacyAccountService {
#Value("${mq.event_argument_key}")
private String eventArgumentKey;
#Value("${range.account_title_code}")
private String accountTitleCode;
private static final Logger log = LoggerFactory.getLogger(SyncLegacyAccountServiceImpl.class);
private final AccountMapRepository accountMapRepository;
private final AccountRequestRepository accountRequestRepository;
private final CustomerRepository customerRepository;
private final CustomerPersonRepository customerPersonRepository;
private final CustomerCompanyRepository customerCompanyRepository;
private final IMQService iMQService;
private final AccountRequestStatusServiceImpl accountRequestStatusServiceImpl;
private final GalaxyApi galaxyApi;
private final RangeApi rangeApi;
private final CustomerMapper customerMapper;
private final InquiryMapper inquiryMapper;
private final AccountRequestMapper accountRequestMapper;
private final EventToAccountRequestEntityMapper eventToAccountRequestMapper;
#Override
public void handleSyncRequest(Event event) {
saveSuccessfulAccountStatus(event); // ****** This is the main issue******
try {
CustomerAccountResponseDto galaxyData = getGalaxyData(event);
Optional<AccountMapEntity> optAccountMapEntity = accountMapRepository.findByNewAccountNo(event.getArgument().get(eventArgumentKey).toString());
if (!optAccountMapEntity.isPresent()) {
//openAccount(event);
} else {
AccountMapEntity accountMapEntity = optAccountMapEntity.get();
CustomerAccountResponseDto customerData = getCustomerData(accountMapEntity);
// save in legacy
}
} catch (Exception exception) {
handleEventRequestException(exception, event);
}
}
private void handleEventRequestException(Exception exception, Event event) {
if (exception instanceof RangeServiceException) {
log.error("Something went wrong with the Range service!");
throw new RangeServiceException();
} else if (exception instanceof GalaxySystemException) {
log.error("Something went wrong with the Galaxy service!");
NotifyAccountChangeResponse notifyAccountChangeResponse = MQUtil.buildAccountChangeResponse(new GalaxySystemException(), null, event.getMessageId());
iMQService.send(notifyAccountChangeResponse);
throw new GalaxySystemException();
}
}
public void saveSuccessfulAccountStatus(Event event) {
AccountRequest accountRequest = eventToAccountRequestMapper.eventToAccountRequest(event, eventArgumentKey);
AccountRequestDto accountRequestDto = accountRequestMapper.toDto(accountRequest);
saveAccountRequestStatus(accountRequestDto, AccountRequestStatusEnum.SUCCESS);
}
public void saveAccountRequestStatus(AccountRequestDto accountRequestDto, AccountRequestStatusEnum status) {
AccountRequestStatusDto accountRequestStatusDto = new AccountRequestStatusDto();
accountRequestStatusDto.setAccountRequestStatusEnum(status);
accountRequestStatusDto.setAccountRequestDto(accountRequestDto);
accountRequestStatusServiceImpl.saveAccountRequestStatus(accountRequestStatusDto);
}
}
UPDATE
AccountRequestStatusServiceImpl
#Service
#Transactional(readOnly = true)
public class AccountRequestStatusServiceImpl implements IAccountRequestStatusService {
private final AccountRequestStatusRepository accountRequestStatusRepository;
private final AccountRequestStatusMapper accountRequestStatusMapper;
#Autowired
public AccountRequestStatusServiceImpl(AccountRequestStatusRepository accountRequestStatusRepository,
AccountRequestStatusMapper accountRequestStatusMapper) {
this.accountRequestStatusRepository = accountRequestStatusRepository;
this.accountRequestStatusMapper = accountRequestStatusMapper;
}
#Override
#Transactional
public void saveAccountRequestStatus(AccountRequestStatusDto accountRequestStatusDto) {
AccountRequestStatus accountRequestStatus = accountRequestStatusMapper.toAccountRequestStatus(accountRequestStatusDto);
accountRequestStatusRepository.save(accountRequestStatus);
}
}
AccountRequestDto
#Data
public class AccountRequestDto {
private Long id;
private String messageId;
private String issuer;
private EventType type;
private EventName name;
private String accountNo;
private LocalDateTime dateTime;
}
AccountRequestStatusDto
#Data
public class AccountRequestStatusDto {
private Long id;
private AccountRequestStatusEnum accountRequestStatusEnum;
private AccountRequestDto accountRequestDto;
}
AccountRequestStatusMapper
#Mapper(componentModel = "spring")
public interface AccountRequestStatusMapper extends EntityToDtoMapper<AccountRequestStatusDto, AccountRequestStatus>, DtoToEntityMapper<AccountRequestStatusDto, AccountRequestStatus> {
#Mapping(target = "accountRequest.id", source = "accountRequestDto.id")
#Mapping(target = "accountRequest.messageId", source = "accountRequestDto.messageId")
#Mapping(target = "accountRequest.issuer", source = "accountRequestDto.issuer")
#Mapping(target = "accountRequest.type", source = "accountRequestDto.type")
#Mapping(target = "accountRequest.name", source = "accountRequestDto.name")
#Mapping(target = "accountRequest.accountNo", source = "accountRequestDto.accountNo")
#Mapping(target = "accountRequest.dateTime", source = "accountRequestDto.dateTime")
#Named(value = "toAccountRequestStatus")
AccountRequestStatus toAccountRequestStatus(AccountRequestStatusDto accountRequestStatusDto);
#Mapping(target = "accountRequestDto.id", source = "accountRequest.id")
#Mapping(target = "accountRequestDto.messageId", source = "accountRequest.messageId")
#Mapping(target = "accountRequestDto.issuer", source = "accountRequest.issuer")
#Mapping(target = "accountRequestDto.type", source = "accountRequest.type")
#Mapping(target = "accountRequestDto.name", source = "accountRequest.name")
#Mapping(target = "accountRequestDto.accountNo", source = "accountRequest.accountNo")
#Mapping(target = "accountRequestDto.dateTime", source = "accountRequest.dateTime")
#Named(value = "toAccountRequestStatusDto")
AccountRequestStatusDto toAccountRequestStatusDto(AccountRequestStatus accountRequestStatus);
}
You are not setting the id field of accountRequestStatus before saving. How is Hibernate supposed to know which entity to update? I'm guessing it is just generating a new id since you don't provide one. You need to somehow get the id of the already created accountRequestStatus and set it before updating. Or alternatively get the persisted accountRequestStatus entity and modify it.
That being said, I think you may be overcomplicating things here. Why does AccountRequestStatus need to be an entity? It does not seem to have an identity itself, it seems more like an attribute of AccountRequest. Can't you just add an AccountRequestStatusEnum field in AccountRequest, being after all a one-to-one relationship? If you are enclosing the status in a class because you foresee it may have more fields in the future, consider making it #Embeddable instead of an #Entity.
The general rule to know if a class must be an #Entity is that it must have an identity. The status of a request does not look like a good candidate, since its identity can simply be that of the request. Having the status be an #Entity means you now have an artificial id, which, surprise, is the root cause of your problem right now. If you want to better understand this topic, I recommend reading into the difference between #Entity and #Embeddable, and if you are feeling theoretical, read a bit about DDD(domain driven design).

Spring JPA, stackoverflow about ManyToMany

I have a ManyToMany relation between EXPERIENCE and COMPETENCE_LEVEL.
I tried:
PROFIL.java:
#Entity
#Table(name="profil")
public class Profil {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id_profil")
private Long idProfil;
public Profil() {
super();
}
public Long getIdProfil() {
return idProfil;
}
public void setIdProfil(Long idProfil) {
this.idProfil = idProfil;
}
#Override
public String toString() {
//[...]
}
}
EXPERIENCE.java:
#Entity
#Table(name="experience")
public class Experience {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id_experience")
private Long idExperience;
#ManyToOne
#JoinColumn(name="id_profil")
private Profil idProfil;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "experience_competence_level", joinColumns = #JoinColumn(name = "id_experience", referencedColumnName = "id_experience"), inverseJoinColumns = #JoinColumn(name = "id_competence_level", referencedColumnName = "id_competence_level"))
private List<CompetenceLevel> competenceLevels;
public Experience() {
super();
idProfil = new Profil();
}
public Long getIdExperience() {
return idExperience;
}
public void setIdExperience(Long idExperience) {
this.idExperience = idExperience;
}
public Profil getIdProfil() {
return idProfil;
}
public void setIdProfil(Profil idProfil) {
this.idProfil = idProfil;
}
public List<CompetenceLevel> getCompetenceLevels() {
return competenceLevels;
}
public void setCompetenceLevels(List<CompetenceLevel> competenceLevels) {
this.competenceLevels = competenceLevels;
}
#Override
public String toString() {
// [...]
}
}
COMPETENCE_LEVEL.java:
#Entity
#Table(name="competence_level")
public class CompetenceLevel {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id_competence_level")
private Long idCompetenceLevel;
#OneToOne
#JoinColumn(name="id_level")
private Level level;
#OneToOne
#JoinColumn(name="id_profil")
private Profil profil;
#ManyToMany(mappedBy = "competenceLevels")
private List<Experience> experiences;
public CompetenceLevel() {
super();
}
public Long getIdCompetenceLevel() {
return idCompetenceLevel;
}
public void setIdCompetenceLevel(Long idCompetenceLevel) {
this.idCompetenceLevel = idCompetenceLevel;
}
public Level getLevel() {
return level;
}
public void setLevel(Level level) {
this.level = level;
}
public Profil getProfil() {
return profil;
}
public void setProfil(Profil profil) {
this.profil = profil;
}
public List<Experience> getExperiences() {
return experiences;
}
public void setExperiences(List<Experience> experiences) {
this.experiences = experiences;
}
#Override
public String toString() {
// [...]
}
}
When I launch a web service which trying to get all my EXPERIENCE, my execution is freezing and it's feels like a stackoverflow issue (i'm not an expert) :/.
But, if I remove the List in CompetenceLevel class, it's working.
I don't understand why. I follow this tuto : https://hellokoding.com/jpa-many-to-many-relationship-mapping-example-with-spring-boot-maven-and-mysql/
Do you have an idea ? Thanks.

NullPointerException when adding Employee in Hibernate

I have a Hibernate Entity "Intranet" which has this code:
// Imports removed
#Entity
#Table(name = "intranets", uniqueConstraints = #UniqueConstraint(columnNames = "company_name"))
#Cacheable
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Intranet {
#Id
#Column(name = "INTRANET_ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private int intranetId;
#Column(name = "owner_id")
private int ownerId;
#Column(name = "setup_done")
private boolean isSetUp = false;
#Column(name = "company_name")
private String companyName;
#ElementCollection
#CollectionTable(name = "employees")
#Column(name = "employee")
private List<Integer> employeeIds;
public int getIntranetId() {
return intranetId;
}
public void setIntranetId(int intranetId) {
this.intranetId = intranetId;
}
public boolean isSetUp() {
return isSetUp;
}
public void setSetUp(boolean isSetUp) {
this.isSetUp = isSetUp;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public int getOwnerId() {
return ownerId;
}
public void setOwnerId(int ownerId) {
this.ownerId = ownerId;
}
public List<Integer> getEmployeeIds() {
return employeeIds;
}
public void setEmployeeIds(List<Integer> employeeIds) {
this.employeeIds = employeeIds;
}
public void addEmployee(int id) {
this.employeeIds.add(id);
}
public void removeEmployee(int id) {
this.employeeIds.remove(new Integer(id));
}
}
As you can see, I added two methods that don't directly are getters and setters but they're like convenience methods to have easy access to the collection and adding/removing employees.
When I call "addEmployee()" in my program, I am getting a simple NullPointerException. The question basically is how I can initialize the collection to not have null because I read that Hibernate uses internal implementations of collections and does not simply takes ArrayList.
Thanks for help in advance.
You have a NullPointerException because you have to initialize the list yourself. It does not matter which implementation you use. This will fix your problem:
#ElementCollection
#Column(name = "employee")
private List<Integer> employeeIds = new ArrayList<>();

hibernate association with n levels

I have two tables (ProspectMaster,ProspectContactsMaster). to maintain a relationship, I made a mapping table(ProspectContactsMap) using an embeddable entity(ProspectContactsMapID). Bellow are the all entities
#Entity
public class ProspectMaster {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int prospectID;
#Column(nullable=false)
#Length(max = 50)
private String companyName;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "prospectContactsMapID.prospectMaster", cascade=CascadeType.ALL)
private Set<ProspectContactsMap> prospectContactsMap = new HashSet<ProspectContactsMap>(0);
public int getProspectID() {
return prospectID;
}
public void setProspectID(int prospectID) {
this.prospectID = prospectID;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public Set<ProspectContactsMap> getProspectContactsMap() {
return prospectContactsMap;
}
public void setProspectContactsMap(Set<ProspectContactsMap> prospectContactsMap) {
this.prospectContactsMap = prospectContactsMap;
}
}
#Entity
public class ProspectContactsMaster {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int prospectContactID;
#Length(max = 25)
private String firstName;
public int getProspectContactID() {
return prospectContactID;
}
public void setProspectContactID(int prospectContactID) {
this.prospectContactID = prospectContactID;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
#Entity
#AssociationOverrides({
#AssociationOverride(name = "prospectContactsMapID.prospectMaster",
joinColumns = #JoinColumn(name = "prospectID")),
#AssociationOverride(name = "prospectContactsMapID.prospectContactsMaster",
joinColumns = #JoinColumn(name = "prospectContactID")) })
public class ProspectContactsMap {
#EmbeddedId
private ProspectContactsMapID prospectContactsMapID = new ProspectContactsMapID();
private int isMainContact;
#Transient
public ProspectMaster getProspectMaster() {
return this.getProspectContactsMapID().getProspectMaster();
}
public void setProspectMaster(ProspectMaster prospectMaster) {
getProspectContactsMapID().setProspectMaster(prospectMaster);
}
#Transient
public ProspectContactsMaster getProspectContactsMaster() {
return this.getProspectContactsMapID().getProspectContactsMaster();
}
public void setProspectContactsMaster(ProspectContactsMaster prospectContactsMaster) {
getProspectContactsMapID().setProspectContactsMaster(prospectContactsMaster);
}
public ProspectContactsMapID getProspectContactsMapID() {
return prospectContactsMapID;
}
public void setProspectContactsMapID(ProspectContactsMapID prospectContactsMapID) {
this.prospectContactsMapID = prospectContactsMapID;
}
public int getIsMainContact() {
return isMainContact;
}
public void setIsMainContact(int isMainContact) {
this.isMainContact = isMainContact;
}
}
#Embeddable
public class ProspectContactsMapID implements Serializable {
#ManyToOne
private ProspectMaster prospectMaster;
#ManyToOne
private ProspectContactsMaster prospectContactsMaster;
public ProspectMaster getProspectMaster() {
return prospectMaster;
}
public void setProspectMaster(ProspectMaster prospectMaster) {
this.prospectMaster = prospectMaster;
}
public ProspectContactsMaster getProspectContactsMaster() {
return prospectContactsMaster;
}
public void setProspectContactsMaster(ProspectContactsMaster prospectContactsMaster) {
this.prospectContactsMaster = prospectContactsMaster;
}
}
now my requirement is to fetch all prospect having company name starts with d or having main contacts starts with d. I have made a query, but in n level I can not provide association property. Bellow is my query
Disjunction disjOrCondition = Restrictions.disjunction();
Criteria cr = getCurrentSession().createCriteria(ProspectMaster.class);
cr.createAlias("prospectContactsMap", "prospectContact");
Criterion thirdCondition = Restrictions.conjunction().add(Restrictions.eq("prospectContact.isMainContact",1))
.add(Restrictions.like("prospectContact.prospectContactsMapID.prospectContactsMaster.firstName", searchVal.toString(),MatchMode.ANYWHERE));
disjOrCondition.add(Restrictions.like("companyName", searchVal.toString(),MatchMode.ANYWHERE));
disjOrCondition.add(thirdCondition);
if I run this, I get bellow exception
org.hibernate.QueryException: could not resolve property: prospectContactsMapID.prospectContactsMaster.firstName
can anyone please tell me where is the problem? and can anyone tell me any example on same. I want to use hql only.
From what I know I just can tell you 2 things:
you can try another fetching strategy; instead of LAZY you could try EAGER
there is a property in the configuration file: hibernate.max_fetch_depth, but i guess you are using the default. It sets the maximum depth for a single-ended asociation.

A cycle is detected in the object graph. This will cause infinitely deep XML

I have two DTO objects say A and B which are having getters and setters and are used to take data from the database. The problem is when I am calling A, B gets called and B again points itself to A and a cycle is created.
I cannot ignore/hide the method which is creating the cycle. I need to take the whole data of A and B.
Is there any way to achieve it ?
Please help
This is my code which is causing the problem. This is application DTO which is calling environment DTO
#OneToMany(mappedBy="application", fetch=FetchType.LAZY
,cascade=CascadeType.ALL
)
public Set<EnvironmentDTO> getEnvironment() {
return environment;
}
public void setEnvironment(Set<EnvironmentDTO> environment) {
this.environment = environment;
}
And this is environment DTO which is calling the application DTO
#ManyToOne(targetEntity=ApplicationDTO.class )
#JoinColumn(name="fk_application_Id")
public ApplicationDTO getApplication() {
return application;
}
public void setApplication(ApplicationDTO application) {
this.application = application;
}
Here cycle is getting created
This is my rest call which will give result in XML format and I think while creating XML cycle is getting created
#GET
#Path("/get")
#Produces({MediaType.APPLICATION_XML})
public List<ApplicationDTO> getAllApplications(){
List<ApplicationDTO> allApplication = applicationService.getAllApplication();
return allApplication;
}
This is the Application DTO class
#Entity
#Table(name="application")
#org.hibernate.annotations.GenericGenerator(
name ="test-increment-strategy",strategy = "increment")
#XmlRootElement
public class ApplicationDTO implements Serializable {
#XmlAttribute
public Long appTypeId;
private static final long serialVersionUID = -8027722210927935073L;
private Long applicationId;
private String applicationName;
private ApplicationTypeDTO applicationType;
private String applicationDescription;
private Integer owner;
private Integer createdBy;
private Integer assignedTo;
private Date createTime;
private Date modifiedTime;
private Set<EnvironmentDTO> environment;
#Id
#GeneratedValue(generator = "test-increment-strategy")
#Column(name = "applicationId")
public Long getApplicationId() {
return applicationId;
}
private void setApplicationId(Long applicationId) {
this.applicationId = applicationId;
}
#Column(name = "applicationName")
public String getApplicationName() {
return applicationName;
}
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
#ManyToOne(targetEntity=ApplicationTypeDTO.class
,fetch = FetchType.LAZY
)
#JoinColumn(name="applicationType")
public ApplicationTypeDTO getApplicationType() {
return applicationType;
}
public void setApplicationType(ApplicationTypeDTO applicationType) {
this.applicationType = applicationType;
}
#Column(name = "description")
public String getApplicationDescription() {
return applicationDescription;
}
public void setApplicationDescription(String applicationDescription) {
this.applicationDescription = applicationDescription;
}
#Column(name = "owner")
public Integer getOwner() {
return owner;
}
public void setOwner(Integer owner) {
this.owner = owner;
}
#Column(name = "createdBy")
public Integer getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Integer createdBy) {
this.createdBy = createdBy;
}
#Column(name = "assignedTo")
public Integer getAssignedTo() {
return assignedTo;
}
public void setAssignedTo(Integer assignedTo) {
this.assignedTo = assignedTo;
}
#Column(name = "createTime")
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
#Column(name = "modifiedTime")
public Date getModifiedTime() {
return modifiedTime;
}
public void setModifiedTime(Date modifiedTime) {
this.modifiedTime = modifiedTime;
}
#OneToMany(mappedBy="application", fetch=FetchType.LAZY
,cascade=CascadeType.ALL
)
public Set<EnvironmentDTO> getEnvironment() {
return environment;
}
public void setEnvironment(Set<EnvironmentDTO> environment) {
this.environment = environment;
}
This is the Environment DTO class
#Entity
#Table(name="environment")
#org.hibernate.annotations.GenericGenerator(
name = "test-increment-strategy",
strategy = "increment")
#XmlRootElement
public class EnvironmentDTO implements Serializable {
#XmlAttribute
public Long envTypeId;
#XmlAttribute
public Long appId;
private static final long serialVersionUID = -2756426996796369998L;
private Long environmentId;
private String environmentName;
private EnvironmentTypeDTO environmentType;
private Integer owner;
private Date createTime;
private Set<InstanceDTO> instances;
private ApplicationDTO application;
#Id
#GeneratedValue(generator = "test-increment-strategy")
#Column(name = "envId")
public Long getEnvironmentId() {
return environmentId;
}
private void setEnvironmentId(Long environmentId) {
this.environmentId = environmentId;
}
#Column(name = "envName")
public String getEnvironmentName() {
return environmentName;
}
public void setEnvironmentName(String environmentName) {
this.environmentName = environmentName;
}
#ManyToOne(targetEntity=EnvironmentTypeDTO.class)
#JoinColumn(name = "envType")
public EnvironmentTypeDTO getEnvironmentType() {
return environmentType;
}
public void setEnvironmentType(EnvironmentTypeDTO environmentType) {
this.environmentType = environmentType;
}
#Column(name = "owner")
public Integer getOwner() {
return owner;
}
public void setOwner(Integer owner) {
this.owner = owner;
}
#Temporal(TemporalType.DATE)
#Column(name = "createTime")
public Date getCreateTime()
{
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
#OneToMany(mappedBy="environment", cascade=CascadeType.ALL, fetch = FetchType.EAGER)
public Set<InstanceDTO> getInstances() {
return instances;
}
public void setInstances(Set<InstanceDTO> instances) {
this.instances = instances;
}
#ManyToOne(targetEntity=ApplicationDTO.class )
#JoinColumn(name="fk_application_Id")
//#XmlTransient
public ApplicationDTO getApplication() {
return application;
}
public void setApplication(ApplicationDTO application) {
this.application = application;
}
Your object graph is cyclic. There is nothing intrinsically wrong with that, and it is a natural consequence of using JPA.
Your problem is not that your object graph is cyclic, but that you are encoding it in a format which cannot handle cycles. This isn't a Hibernate question, it's a JAXB question.
My suggestion would be to stop JAXB from attempting to marshal the application property of the EnvironmentDTO class. Without that property the cyclic graph becomes a tree. You can do this by annotating that property with #XmlTransient.
(confession: i learned about this annotation by reading a blog post by Mr Doughan, which i came across after reading his answer to this question!)
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
MOXy offers the #XmlInverseReference extension to handle this use case. Below is an example of how to apply this mapping on two entities with a bidirectional relationship.
Customer
import javax.persistence.*;
#Entity
public class Customer {
#Id
private long id;
#OneToOne(mappedBy="customer", cascade={CascadeType.ALL})
private Address address;
}
Address
import javax.persistence.*;
import org.eclipse.persistence.oxm.annotations.*;
#Entity
public class Address implements Serializable {
#Id
private long id;
#OneToOne
#JoinColumn(name="ID")
#MapsId
#XmlInverseReference(mappedBy="address")
private Customer customer;
}
For More Information
http://blog.bdoughan.com/2010/07/jpa-entities-to-xml-bidirectional.html
http://blog.bdoughan.com/2013/03/moxys-xmlinversereference-is-now-truly.html
My advice is not exposing your JPA entity class to your webservices. You can create different POJO class and convert your JPA entity to the POJO. For example:
this is your JPA entity
import javax.persistence.*;
#Entity
public class Customer {
#Id
private long id;
#OneToOne(mappedBy="customer", cascade={CascadeType.ALL})
private Address address;
}
you should use this class for your webservices:
public class CustomerModel{
private long id;
//you can call different WS to get the Address class, or combine to this model
public void setFromJpa(Customer customer){
this.id = customer.id;
}
}

Categories