I'd like to use mapstruct to deepclone same objects. However situation is little bit trickier as I'm using abstraction.
public abstract class Fruit {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
public class Banana extends Fruit {
private String origin;
public String getOrigin() {
return origin;
}
public void setOrigin(String origin) {
this.origin = origin;
}
}
public class Apple extends Fruit {
private String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
#Mapper(mappingControl = DeepClone.class, subclassExhaustiveStrategy = SubclassExhaustiveStrategy.RUNTIME_EXCEPTION)
public interface FruitMapper {
#SubclassMapping(source = Apple.class, target = Apple.class)
#SubclassMapping(source = Banana.class, target = Banana.class)
Fruit clone(Fruit fruit);
}
and finally this is what is generated:
public class FruitMapperImpl implements FruitMapper {
#Override
public Fruit clone(Fruit fruit) {
if ( fruit == null ) {
return null;
}
if (fruit instanceof Apple) {
return (Apple) fruit;
}
else if (fruit instanceof Banana) {
return (Banana) fruit;
}
else {
throw new IllegalArgumentException("Not all subclasses are supported for this mapping. Missing for " + fruit.getClass());
}
}
}
The thing I'm missing is the actual implementation of given subclasses. Is that a bug or is it designed like this?
Because if I add method like Apple clone(Apple apple); then it should be good (for Apple only) however I don't see any benefit of adding SubclassMapping
public class FruitMapperImpl implements FruitMapper {
#Override
public Fruit clone(Fruit fruit) {
if ( fruit == null ) {
return null;
}
if (fruit instanceof Apple) {
return clone( (Apple) fruit );
}
else if (fruit instanceof Banana) {
return (Banana) fruit;
}
else {
throw new IllegalArgumentException("Not all subclasses are supported for this mapping. Missing for " + fruit.getClass());
}
}
#Override
public Apple clone(Apple apple) {
if ( apple == null ) {
return null;
}
Apple apple1 = new Apple();
apple1.setId( apple.getId() );
apple1.setType( apple.getType() );
return apple1;
}
}
EDIT:
issue created
Related
I can find answers where we have String to Enum mapping but I can't find how can I map an Enum to a String.
public class Result {
Value enumValue;
}
public enum Value {
TEST,
NO TEST
}
public class Person {
String value;
}
How can I map this ?
I tried :
#Mapping(target = "value", source = "enumValue", qualifiedByName = "mapValue")
#Named("mapValue")
default Person mapValue(final Value en) {
return Person.builder().value(en.name()).build();
}
mapstruct should support this out of the box.
So #Mapping(target = "value", source = "enumValue") should suffice.
Complete example including target/source classes:
#Mapper
public interface EnumMapper {
#Mapping( target = "value", source = "enumValue" )
Person map(Result source);
}
class Result {
private Value enumValue;
public Value getEnumValue() {
return enumValue;
}
public void setEnumValue(Value enumValue) {
this.enumValue = enumValue;
}
}
enum Value {
TEST, NO_TEST
}
class Person {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
This results in the following generated code:
#Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2022-02-20T12:33:00+0100",
comments = "version: 1.5.0.Beta2, compiler: Eclipse JDT (IDE) 1.4.50.v20210914-1429, environment: Java 17.0.1 (Azul Systems, Inc.)"
)
public class EnumMapperImpl implements EnumMapper {
#Override
public Person map(Result source) {
if ( source == null ) {
return null;
}
Person person = new Person();
if ( source.getEnumValue() != null ) {
person.setValue( source.getEnumValue().name() );
}
return person;
}
}
I have an application with uses multiple contexts for EF, some are code first, some server first, and all are dynamic.
I have a class that I call to get these contexts in my app.
Each context implements an interface such as:
public interface IDatabaseContextSwitcher
{
IVGSContext GetDatabase(string organization);
IVGSContext GetDatabase(Guid organizationGuid, string email);
IVGSServerConn GetServerDatabase(string databaseName);
IAuthContext GetAuthorizationDatabase();
}
I therefore has a class that implments the instances of these interfaces in the application. (VGSContext, VGSServerConn, and AuthContext).
I am trying to test these in my test project. I have made new classes from the interfaces with the plan to plug in some DbSets into these new classes and then test that my controllers do the correct thing.
However, I can't seem to figure out how to initialize the DBSets.
For example the following dies on Add:
public AuthContextForTesting()
{
Organizations.Add(new Organization()
{OrganizationName = "Test1", PK_Organization = Guid.Parse("34CE4F83-B3C9-421B-B1F3-42BBCDA9A004")});
var cnt = Organizations.Count();
}
public DbSet<Organization> Organizations { get; set; }
I tried to initialize the DBSet with:
Organizations=new DbSet();
But it gives an error that this is not allowed due to permissions.
How do I set up my initial dbsets in code for my tests?
To be able to do this, you first have to derive a class from DBSet. Sadly, my app uses both Core EF and EF 6 so I had to create 2 classes.
EF 6 Class
public class FakeDbSet<T> : System.Data.Entity.DbSet<T>, IDbSet<T> where T : class
{
List<T> _data;
public FakeDbSet()
{
_data = new List<T>();
}
public override T Find(params object[] keyValues)
{
throw new NotImplementedException("Derive from FakeDbSet<T> and override Find");
}
public override T Add(T item)
{
_data.Add(item);
return item;
}
public override T Remove(T item)
{
_data.Remove(item);
return item;
}
public override T Attach(T item)
{
return null;
}
public T Detach(T item)
{
_data.Remove(item);
return item;
}
public override T Create()
{
return Activator.CreateInstance<T>();
}
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T
{
return Activator.CreateInstance<TDerivedEntity>();
}
public List<T> Local
{
get { return _data; }
}
public override IEnumerable<T> AddRange(IEnumerable<T> entities)
{
_data.AddRange(entities);
return _data;
}
public override IEnumerable<T> RemoveRange(IEnumerable<T> entities)
{
for (int i = entities.Count() - 1; i >= 0; i--)
{
T entity = entities.ElementAt(i);
if (_data.Contains(entity))
{
Remove(entity);
}
}
return this;
}
Type IQueryable.ElementType
{
get { return _data.AsQueryable().ElementType; }
}
System.Linq.Expressions.Expression IQueryable.Expression
{
get { return _data.AsQueryable().Expression; }
}
IQueryProvider IQueryable.Provider
{
get { return _data.AsQueryable().Provider; }
}
IEnumerator IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return _data.GetEnumerator();
}
}
The EF Core had to include some interfaces to work.
public class FakeCoreDbSet<T> : Microsoft.EntityFrameworkCore.DbSet<T> , IQueryable, IEnumerable<T> where T : class
{
List<T> _data;
public FakeCoreDbSet()
{
_data = new List<T>();
}
public override T Find(params object[] keyValues)
{
throw new NotImplementedException("Derive from FakeDbSet<T> and override Find");
}
public override EntityEntry<T> Add(T item)
{
_data.Add(item);
//return item;
return null;
}
public override EntityEntry<T> Remove(T item)
{
_data.Remove(item);
//return item;
return null;
}
public override EntityEntry<T> Attach(T item)
{
return null;
}
public T Detach(T item)
{
_data.Remove(item);
return item;
}
public IList GetList()
{
return _data.ToList();
}
//public override T Create()
//{
// return Activator.CreateInstance<T>();
//}
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T
{
return Activator.CreateInstance<TDerivedEntity>();
}
public List<T> Local
{
get { return _data; }
}
public override void AddRange(IEnumerable<T> entities)
{
_data.AddRange(entities);
//return _data;
}
public override void RemoveRange(IEnumerable<T> entities)
{
for (int i = entities.Count() - 1; i >= 0; i--)
{
T entity = entities.ElementAt(i);
if (_data.Contains(entity))
{
Remove(entity);
}
}
// this;
}
Type IQueryable.ElementType
{
get { return _data.AsQueryable().ElementType; }
}
System.Linq.Expressions.Expression IQueryable.Expression
{
get { return _data.AsQueryable().Expression; }
}
IQueryProvider IQueryable.Provider
{
get { return _data.AsQueryable().Provider; }
}
IEnumerator IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return _data.GetEnumerator();
}
}
Once these were created I could use MockObjects to get to them.
Note _dbContextSwitcher is the class created with a Moq that calls the different databases.
var vgsdatabase = new Mock<IVGSContext>();
var settings=new FakeCoreDbSet<Setting>();
settings.Add(new Setting()
{
SettingID = "OrgPrivacy",
PK_Setting = Guid.NewGuid(),
UserID = "",
Value = "No"
});
vgsdatabase.Setup(s => s.Setting).Returns(settings);
_dbcontextSwitcher.Setup(s => s.GetDatabase(It.IsAny<string>())).Returns(vgsdatabase.Object);
I have the below function and am getting an error on the second line saying Unspecified value parameters :: type[T], Type mismatch, expected: Command[NotInferedT], actual: DeletePrivilegeMappingCmd.
execute() takes in a parameter of Command[T] and DeletePrivilegeMappingCmd extends that Command[T] requirement.
I figured out based on the error I need to add a [Object] to the signature, but I'm not sure what Type I have to include inside the []. Adding any Object gets rid of the error, but I'm assuming there will be a runtime error if the correct type is not used.
What type am I supposed to add?
Error message signature
def deleteGroupPrivilegeMapping(privilegeId: String, groupId: String) {
commandExecutor.execute(new DeletePrivilegeMappingCmd(privilegeId, null, groupId))
}
Updated message signature
def deleteGroupPrivilegeMapping(privilegeId: String, groupId: String) {
commandExecutor.execute(new DeletePrivilegeMappingCmd(privilegeId, null, groupId)[String][String])
}
EDIT:
Signature for Command and execute
public interface Command<T> extends BaseCommand<T, CommandContext> {
T execute(CommandContext commandContext);
}
Implementation for DeletePrivilegeMappingCmd
public class DeletePrivilegeCmd implements Command<Void>, Serializable {
private static final long serialVersionUID = 1L;
protected String id;
public DeletePrivilegeCmd(String id) {
if (id == null) {
throw new FlowableIllegalArgumentException("id is null");
}
this.id = id;
}
public Void execute(CommandContext commandContext) {
commandContext.gePrivilegeMappingEntityManager().deleteByPrivilegeId(id);
commandContext.getPrivilegeEntityManager().delete(id);
return null;
}
}
Command Context Definition
public class CommandContext extends AbstractCommandContext {
private static Logger log = LoggerFactory.getLogger(CommandContext.class);
protected ProcessEngineConfigurationImpl processEngineConfiguration;
protected FailedJobCommandFactory failedJobCommandFactory;
protected FlowableEngineAgenda agenda;
protected Map<String, ExecutionEntity> involvedExecutions = new HashMap(1);
protected LinkedList<Object> resultStack = new LinkedList();
public CommandContext(Command<?> command, ProcessEngineConfigurationImpl processEngineConfiguration) {
super(command);
this.processEngineConfiguration = processEngineConfiguration;
this.failedJobCommandFactory = processEngineConfiguration.getFailedJobCommandFactory();
this.sessionFactories = processEngineConfiguration.getSessionFactories();
this.agenda = processEngineConfiguration.getAgendaFactory().createAgenda(this);
}
protected void logException() {
if(!(this.exception instanceof JobNotFoundException) && !(this.exception instanceof FlowableTaskAlreadyClaimedException)) {
super.logException();
} else {
log.info("Error while closing command context", this.exception);
}
}
public void addCloseListener(CommandContextCloseListener commandContextCloseListener) {
if(this.closeListeners == null) {
this.closeListeners = new ArrayList(1);
}
this.closeListeners.add(commandContextCloseListener);
}
public DbSqlSession getDbSqlSession() {
return (DbSqlSession)this.getSession(DbSqlSession.class);
}
public EntityCache getEntityCache() {
return (EntityCache)this.getSession(EntityCache.class);
}
public DeploymentEntityManager getDeploymentEntityManager() {
return this.processEngineConfiguration.getDeploymentEntityManager();
}
public ResourceEntityManager getResourceEntityManager() {
return this.processEngineConfiguration.getResourceEntityManager();
}
public ByteArrayEntityManager getByteArrayEntityManager() {
return this.processEngineConfiguration.getByteArrayEntityManager();
}
public ProcessDefinitionEntityManager getProcessDefinitionEntityManager() {
return this.processEngineConfiguration.getProcessDefinitionEntityManager();
}
public ModelEntityManager getModelEntityManager() {
return this.processEngineConfiguration.getModelEntityManager();
}
public ProcessDefinitionInfoEntityManager getProcessDefinitionInfoEntityManager() {
return this.processEngineConfiguration.getProcessDefinitionInfoEntityManager();
}
public ExecutionEntityManager getExecutionEntityManager() {
return this.processEngineConfiguration.getExecutionEntityManager();
}
public TaskEntityManager getTaskEntityManager() {
return this.processEngineConfiguration.getTaskEntityManager();
}
public IdentityLinkEntityManager getIdentityLinkEntityManager() {
return this.processEngineConfiguration.getIdentityLinkEntityManager();
}
public VariableInstanceEntityManager getVariableInstanceEntityManager() {
return this.processEngineConfiguration.getVariableInstanceEntityManager();
}
public HistoricProcessInstanceEntityManager getHistoricProcessInstanceEntityManager() {
return this.processEngineConfiguration.getHistoricProcessInstanceEntityManager();
}
public HistoricDetailEntityManager getHistoricDetailEntityManager() {
return this.processEngineConfiguration.getHistoricDetailEntityManager();
}
public HistoricVariableInstanceEntityManager getHistoricVariableInstanceEntityManager() {
return this.processEngineConfiguration.getHistoricVariableInstanceEntityManager();
}
public HistoricActivityInstanceEntityManager getHistoricActivityInstanceEntityManager() {
return this.processEngineConfiguration.getHistoricActivityInstanceEntityManager();
}
public HistoricTaskInstanceEntityManager getHistoricTaskInstanceEntityManager() {
return this.processEngineConfiguration.getHistoricTaskInstanceEntityManager();
}
public HistoricIdentityLinkEntityManager getHistoricIdentityLinkEntityManager() {
return this.processEngineConfiguration.getHistoricIdentityLinkEntityManager();
}
public EventLogEntryEntityManager getEventLogEntryEntityManager() {
return this.processEngineConfiguration.getEventLogEntryEntityManager();
}
public JobEntityManager getJobEntityManager() {
return this.processEngineConfiguration.getJobEntityManager();
}
public TimerJobEntityManager getTimerJobEntityManager() {
return this.processEngineConfiguration.getTimerJobEntityManager();
}
public SuspendedJobEntityManager getSuspendedJobEntityManager() {
return this.processEngineConfiguration.getSuspendedJobEntityManager();
}
public DeadLetterJobEntityManager getDeadLetterJobEntityManager() {
return this.processEngineConfiguration.getDeadLetterJobEntityManager();
}
public AttachmentEntityManager getAttachmentEntityManager() {
return this.processEngineConfiguration.getAttachmentEntityManager();
}
public TableDataManager getTableDataManager() {
return this.processEngineConfiguration.getTableDataManager();
}
public CommentEntityManager getCommentEntityManager() {
return this.processEngineConfiguration.getCommentEntityManager();
}
public PropertyEntityManager getPropertyEntityManager() {
return this.processEngineConfiguration.getPropertyEntityManager();
}
public EventSubscriptionEntityManager getEventSubscriptionEntityManager() {
return this.processEngineConfiguration.getEventSubscriptionEntityManager();
}
public HistoryManager getHistoryManager() {
return this.processEngineConfiguration.getHistoryManager();
}
public JobManager getJobManager() {
return this.processEngineConfiguration.getJobManager();
}
public void addInvolvedExecution(ExecutionEntity executionEntity) {
if(executionEntity.getId() != null) {
this.involvedExecutions.put(executionEntity.getId(), executionEntity);
}
}
public boolean hasInvolvedExecutions() {
return this.involvedExecutions.size() > 0;
}
public Collection<ExecutionEntity> getInvolvedExecutions() {
return this.involvedExecutions.values();
}
public FailedJobCommandFactory getFailedJobCommandFactory() {
return this.failedJobCommandFactory;
}
public ProcessEngineConfigurationImpl getProcessEngineConfiguration() {
return this.processEngineConfiguration;
}
public FlowableEventDispatcher getEventDispatcher() {
return this.processEngineConfiguration.getEventDispatcher();
}
public FlowableEngineAgenda getAgenda() {
return this.agenda;
}
public Object getResult() {
return this.resultStack.pollLast();
}
public void setResult(Object result) {
this.resultStack.add(result);
}
}
UPDATED: I've taken Chris's answer into account but it didn't help - I'm still facing the issue. I've updated the code below to incorporate Chris's answer. Something to note is that when implementing Chris's suggestion, the relations were persisted but not reflected on the view.xhtml page. I had to replace the db object with the object returned form the call to GenericDao.update().
I've got the following relations:
One Customer to many PurchaseOrders (PO)
One PO to many Invoices.
I've read up on bi-directional relations and I know that if I have a bi-directional relation, I should update both sides of the relation when updating entities.
I perform the following steps:
Create a customer (Customer 1)
Create a purchase order (Order 1) linked to Customer 1
Create an invoice (Invoice 1) linked to Order 1.
What I observe is that all entities and relations are persisted but the list of Customer's Orders is not displayed.
view Customer:
view PurchaseOrder:
DB queries:
> select * from customer;
> +----+------------+
> | ID | NAME |
> +----+------------+
> | 1 | Customer 1 |
> +----+------------+
> 1 row in set (0.00 sec)
>
> mysql> select * from purchaseorder;
> +----+---------+-------------+
> | ID | NAME | customer_id |
> +----+---------+-------------+
> | 1 | Order 1 | 1 |
> +----+---------+-------------+
> 1 row in set (0.00 sec)
>
> mysql> select * from invoice;
> +----+-----------+------------------+
> | ID | NAME | purchaseorder_id |
> +----+-----------+------------------+
> | 1 | Invoice 1 | 1 |
> +----+-----------+------------------+
> 1 row in set (0.00 sec)
The DB reflects the relation between the configured entities so I know my changes are being persisted and, as far as I can tell, I've implemented the Customer-PO relation the same ways as the PO-Invoice relation. Since the list of Invoices for PO is updated correctly, I don't think I have a systemic issue so there must be something different between the implementation of Customers-PO and PO-Invoices relations but I can't spot it.
Why don't I see a list of PO's for my Customer even though there are clearly PO's configured for the customer?
Any help will be appreciated.
Classes(truncated for brevity):
Entities
Customer
private int id; //#Id and #GeneratedValue(IDENTITY) on getter
private String name;
#OneToMany(mappedBy="customer")
private Set<PurchaseOrder> purchaseOrders;
public Customer()
{
purchaseOrders = new HashSet<PurchaseOrder> ();
}
public Set<PurchaseOrder> getPurchaseOrders()
{
return this.purchaseOrders;
}
public void setPurchaseOrders(Set<PurchaseOrder> orders)
{
this.purchaseOrders = orders;
}
public void addPurchaseOrder(PurchaseOrder purchaseOrder)
{
this.purchaseOrders.add(purchaseOrder);
//this IF is important for avoiding an infinite loop
if (purchaseOrder.getCustomer() != this)
{
purchaseOrder.setCustomer(this);
}
}
public void removePurchaseOrder(PurchaseOrder purchaseOrder)
{
this.purchaseOrders.remove(purchaseOrder);
//this IF is important to avoid an infinite loop
if(purchaseOrder.getCustomer() != null)
{
purchaseOrder.removeFromCustomer(this);
}
}
PO
private int id; //#Id and identity column
private String name;
#ManyToOne
#JoinColumn(name="customer_id")
private Customer customer;
#OneToMany(mappedBy="purchaseOrder")
private Set<Invoice> invoices;
public PurchaseOrder() {
invoices = new HashSet<Invoice> ();
}
public Customer getCustomer()
{
return this.customer;
}
public void setCustomer(Customer customer)
{
this.customer = customer;
}
public void addToCustomer(Customer customer)
{
//this IF is important for avoiding an infinite loop
if(!customer.getPurchaseOrders().contains(this))
{
customer.addPurchaseOrder(this);
}
this.customer = customer;
}
public void removeFromCustomer(Customer customer)
{
//this IF is important for avoiding an infinite loop
if(customer.getPurchaseOrders().contains(this))
{
customer.removePurchaseOrder(this);
}
this.customer = null;
}
public Set<Invoice> getInvoices()
{
return this.invoices;
}
public void setInvoices(Set<Invoice> invoices)
{
this.invoices = invoices;
}
public void addInvoice(Invoice invoice)
{
this.invoices.add(invoice);
//this IF is important for avoiding an infinite loop
if (invoice.getPurchaseOrder() != this)
{
invoice.addToPurchaseOrder(this);
}
}
public void removeInvoice(Invoice invoice)
{
this.invoices.remove(invoice);
//this IF is important to avoid an infinite loop
if(invoice.getPurchaseOrder() != null)
{
invoice.removeFromPurchaseOrder(this);
}
}
Invoice
private int id; //#Id and identity column
private String name;
#ManyToOne
#JoinColumn(name="purchaseorder_id")
private PurchaseOrder purchaseOrder;
public Invoice() {
}
public PurchaseOrder getPurchaseOrder()
{
return this.purchaseOrder;
}
public void setPurchaseOrder(PurchaseOrder purchaseOrder)
{
this.purchaseOrder = purchaseOrder;
}
public void addToPurchaseOrder(PurchaseOrder purchaseOrder)
{
//this IF is important for avoiding an infinite loop
if(!purchaseOrder.getInvoices().contains(this))
{
purchaseOrder.addInvoice(this);
}
this.purchaseOrder = purchaseOrder;
}
public void removeFromPurchaseOrder(PurchaseOrder purchaseOrder)
{
//this IF is important for avoiding an infinite loop
if(purchaseOrder.getInvoices().contains(this))
{
purchaseOrder.removeInvoice(this);
}
this.purchaseOrder = null;
}
GenericDao (Parent of all other DAOs)
#Stateful
public class GenericDao<T extends Serializable, PK> implements IGenericDao<T, PK>
{
#PersistenceContext(unitName = "my_PU")
protected EntityManager em;
private Class<T> type;
public Class<T> getType()
{
return type;
}
public void setType(Class<T> type)
{
this.type = type;
}
public void create(T newObject)
{
em.persist(newObject);
}
public T read(PK id)
{
return em.find(type, id);
}
public T update(T transientObject)
{
return em.merge(transientObject);
}
public void delete(T objectToDelete)
{
em.remove(objectToDelete);
}
public T getResultObject(String namedQuery, Map<String, Object> criteria)
throws DatabaseException
{
List<T> records = getResultSetList(namedQuery, criteria);
if(records.isEmpty())
{
return null;
}
else if (records.size() != 1)
{
throw new DatabaseException("Too many records found!");
}
else
{
return records.remove(0);
}
}
}
Controllers
CustomerController
#RequestScoped
public class CustomerController extends FormRequestController
{
#Inject
private HTMLDataTableActionBean htmlDataTableActionBean;
#EJB
private ICustomerDao customerDao;
#Inject
private Customer customer;
#PostConstruct
public void init() throws DatabaseException
{
setEntityObjectList(findAll());
if (null == this.getCustomer())
{
setCustomer(new Customer());
}
}
public void processRequest(FormActionToPerform action) throws DatabaseException
{
switch (action)
{
case SHOW_ADD_VIEW:
setCustomer(new Customer());
break;
case SHOW_VIEW_FOR_LIST:
setEntityObjectList(findAll());
break;
case SHOW_EDIT_VIEW:
case SHOW_VIEW_TO_VIEW_SELECTED_OBJECT:
setCustomer((Customer) getHtmlDataTableActionBean()
.getSelectedEntityObject());
break;
case SHOW_DELETE_VIEW:
setCustomer((Customer) getHtmlDataTableActionBean()
.getSelectedEntityObject());
delete();
break;
}
}
public String doShowUIView(FormActionToPerform action)
{
String responseURL = "fail.xhtml";
if (null == this.customer)
{
return responseURL;
}
else
{
switch (action)
{
case SHOW_ADD_VIEW:
responseURL = "customer.xhtml";
break;
case SHOW_EDIT_VIEW:
responseURL = "customer.xhtml";
break;
case SHOW_VIEW_TO_VIEW_SELECTED_OBJECT:
responseURL = "viewCustomer.xhtml";
break;
case SHOW_DELETE_VIEW:
responseURL = "customerList.xhtml";
break;
case SHOW_VIEW_FOR_LIST:
if (this.entityObjectList.size() == 0)
{
setErrorMessage("No customers to display");
}
responseURL = "customerList.xhtml";
break;
default:
responseURL = "index.xhtml";
}
}
return responseURL;
}
public String save()
{
String url = "success.xhtml";
Customer existingCustomer = null;
try
{
existingCustomer =
customerDao.getCustomerByName(this.getCustomer().getName());
if(existingCustomer != null)
{
//there's already a customer with this name, don't make a new one
setErrorMessage("Customer already exists");
url = "fail.xhtml";
}
customerDao.update(customer);
}
catch (DatabaseException e)
{
setErrorMessage(e.toString());
e.printStackTrace();
url = "fail.xhtml";
}
return url;
}
}
POController
#RequestScoped
public class PurchaseOrderController extends FormRequestController
{
#Inject
private HTMLDataTableActionBean htmlDataTableActionBean;
#EJB
private IPurchaseOrderDao purchaseOrderDao;
#EJB
private IInvoiceDao invoiceDao;
#EJB
private ICustomerDao customerDao;
#Inject
private PurchaseOrder purchaseOrder;
private List<SelectItem> customerList;
private String selectedCustomer;
#PostConstruct
public void init() throws DatabaseException
{
setEntityObjectList(findAll());
if (null == purchaseOrder)
{
purchaseOrder = new PurchaseOrder();
setEditMode(false);
}
}
public void processRequest(FormActionToPerform action)
throws DatabaseException
{
switch (action)
{
case SHOW_ADD_VIEW:
setPurchaseOrder(new PurchaseOrder());
break;
case SHOW_VIEW_FOR_LIST:
setEntityObjectList(findAll());
break;
case SHOW_EDIT_VIEW:
case SHOW_VIEW_TO_VIEW_SELECTED_OBJECT:
{
setPurchaseOrder(
(PurchaseOrder)getHtmlDataTableActionBean().
getSelectedEntityObject());
}
break;
case SHOW_DELETE_VIEW:
{
setPurchaseOrder(
(PurchaseOrder)getHtmlDataTableActionBean().
getSelectedEntityObject());
delete();
}
break;
}
}
String doShowUIView(FormActionToPerform action)
{
String responseURL = "fail.xhtml";
switch (action)
{
case SHOW_ADD_VIEW:
responseURL = "purchaseOrder.xhtml";
break;
case SHOW_EDIT_VIEW:
setEditMode(true);
setComponent(null);
responseURL = "purchaseOrder.xhtml";
break;
case SHOW_DELETE_VIEW:
case SHOW_VIEW_FOR_LIST:
if (this.entityObjectList.size() == 0)
{
setErrorMessage("No orders to display");
}
responseURL = "purchaseOrderList.xhtml";
break;
case SHOW_VIEW_TO_VIEW_SELECTED_OBJECT:
responseURL = "viewPurchaseOrder.xhtml";
break;
default:
responseURL = HOME;
}
return responseURL;
}
public String save()
{
String responseURL = "fail.xhtml";
try
{
PurchaseOrder dbPurchaseOrder =
purchaseOrderDao.getPurchaseOrderByName(purchaseOrder.getName());
if(dbPurchaseOrder == null)
{
dbPurchaseOrder = purchaseOrder;
}
Customer customer = customerDao.getCustomerByName(selectedCustomer);
dbPurchaseOrder.addToCustomer(customer);
purchaseOrder = purchaseOrderDao.update(dbPurchaseOrder);
//replace the not-yet-persisted dbPurchaseOrder object in customer
//with the persisted purchaseOrderobject returned from the update()
//call above.
customer.removePurchaseOrder(dbPurchaseOrder);
customer.addPurchaseOrder(purchaseOrder);
customerDao.update(customer);
System.out.println("# of Purchase orders for customer: "+
purchaseOrder.getCustomer().getPurchaseOrders().size());
//Output: # of Purchase orders for customer: 1
responseURL = "success.xhtml";
}
catch (DatabaseException e)
{
e.printStackTrace();
setErrorMessage(e.toString());
responseURL = null;
}
return responseURL;
}
}
InvoicesController
#RequestScoped
public class InvoiceController extends FormRequestController
{
#Inject
private HTMLDataTableActionBean htmlDataTableActionBean;
#EJB
private IInvoiceDao invoiceDao;
#Inject
private Invoice invoice;
#EJB
private IPurchaseOrderDao purchaseOrderDao;
private List<SelectItem> purchaseOrderList;
private String selectedPurchaseOrder;
#PostConstruct
public void init() throws DatabaseException
{
setEntityObjectList(findAll());
if (null == invoice)
{
invoice = new Invoice();
setEditMode(false);
}
}
public void processRequest(FormActionToPerform action) throws DatabaseException
{
switch (action)
{
case SHOW_ADD_VIEW:
break;
case SHOW_VIEW_FOR_LIST:
setEntityObjectList(findAll());
break;
case SHOW_EDIT_VIEW:
case SHOW_VIEW_TO_VIEW_SELECTED_OBJECT:
{
setInvoice((Invoice)getHtmlDataTableActionBean().
getSelectedEntityObject());
}
break;
case SHOW_DELETE_VIEW:
{
setInvoice((Invoice)getHtmlDataTableActionBean().
getSelectedEntityObject());
delete();
}
break;
}
}
String doShowUIView(FormActionToPerform action)
{
String responseUrl = "fail.xhtml";
if (null == invoice)
{
System.out.println("invoice == null");
return responseUrl;
}
else
{
switch (action)
{
case SHOW_ADD_VIEW:
responseUrl = "invoice.xhtml";
break;
case SHOW_EDIT_VIEW:
setEditMode(true);
setComponent(null);
responseUrl = "invoice.xhtml";
break;
case SHOW_VIEW_TO_VIEW_SELECTED_OBJECT:
responseUrl = "viewInvoice.xhtml";
break;
case SHOW_DELETE_VIEW:
case SHOW_VIEW_FOR_LIST:
if (this.entityObjectList.size() == 0)
{
setErrorMessage("no invoices to display");
}
responseUrl = "invoiceList.xhtml";
break;
default:
responseUrl = "index.xhtml";
}
}
return responseUrl;
}
public String save()
{
String responseUrl = "fail.xhtml";
try
{
Invoice dbInvoice = invoiceDao.getInvoiceByName(invoice.getName());
if(dbInvoice == null)
{
//this is a new invoice
dbInvoice = invoice;
}
PurchaseOrder purchaseOrder =
purchaseOrderDao.getPurchaseOrderByName(selectedPurchaseOrder);
dbInvoice.addToPurchaseOrder(purchaseOrder);
invoice = invoiceDao.update(dbInvoice);
//replace the not-yet-persisted dbInvoice object in purchaseOrder
//with the persisted invoice object returned from the update() call above.
purchaseOrder.removeInvoice(dbInvoice);
purchaseOrder.addInvoice(invoice);
purchaseOrderDao.update(purchaseOrder);
System.out.println("# of Invoices for purchase order: "+
invoice.getPurchaseOrder().getInvoices().size());
//Output: # of Invoices for purchase order: 1
responseUrl = "success.xhtml";
}
catch (Exception e)
{
System.out.println(e.toString());
e.printStackTrace();
setErrorMessage(e.toString());
}
return responseUrl;
}
}
FormRequestController
public abstract class FormRequestController implements NavigationConstants
{
protected enum FormActionToPerform {
SHOW_ADD_VIEW,
SHOW_EDIT_VIEW,
SHOW_DELETE_VIEW,
SHOW_VIEW_TO_VIEW_SELECTED_OBJECT,
SHOW_VIEW_FOR_LIST;
}
protected FacesContext context;
protected List<?> entityObjectList;
private UIComponent component;
protected boolean editMode;
protected String componentId = null;
public String showViewDataTable() throws DatabaseException {
processRequest(FormActionToPerform.SHOW_VIEW_FOR_LIST);
return doShowUIView(FormActionToPerform.SHOW_VIEW_FOR_LIST);
}
public String showViewToAdd() throws DatabaseException {
processRequest(FormActionToPerform.SHOW_ADD_VIEW);
return doShowUIView(FormActionToPerform.SHOW_ADD_VIEW);
}
public String showViewToEdit() throws DatabaseException {
processRequest(FormActionToPerform.SHOW_EDIT_VIEW);
return doShowUIView(FormActionToPerform.SHOW_EDIT_VIEW);
}
public String showViewToDeleteDetails() throws DatabaseException {
processRequest(FormActionToPerform.SHOW_DELETE_VIEW);
return doShowUIView(FormActionToPerform.SHOW_DELETE_VIEW);
}
public String showViewToViewDetails() throws DatabaseException {
processRequest(FormActionToPerform.SHOW_VIEW_TO_VIEW_SELECTED_OBJECT);
return doShowUIView(FormActionToPerform.SHOW_VIEW_TO_VIEW_SELECTED_OBJECT);
}
abstract String doShowUIView(FormActionToPerform action);
abstract void processRequest(FormActionToPerform action) throws DatabaseException;
protected void bindData() {
}
abstract String save();
abstract void delete() throws DatabaseException;
public List<?> getEntityObjectList() {
return entityObjectList;
}
public void setEntityObjectList(List<?> entityObjectList) {
this.entityObjectList = entityObjectList;
}
public FacesContext getContext() {
setContext(FacesContext.getCurrentInstance());
return context;
}
public void setContext(FacesContext context) {
this.context = context;
}
public UIComponent getComponent() {
return component;
}
public void setComponent(UIComponent component) {
this.component = component;
}
}
I'm iterating over the Customer#purchaseOrders and PurchaseOrder#invoices using a h:dataTable. SO keeps misidentifying my JSF code as misformatted code and telling me to indent it as such so I can't show my webpage code but hopefully there's enough above to spot my mistake.
Thanks in advance for your time.
You should not have logic within the set/get methods if JPA is set to use property access. The logic within the set methods will cause JPA to trigger lazy collections etc when building entities and might have other adverse affects depending on the provider internals. I would either switch your annotations so they are on the fields, or remove the
if(!purchaseOrder.getInvoices().contains(this))
{
purchaseOrder.addInvoice(this);
}
logic from the set methods. The application can still use the addInvoice and have it set both sides of the relationship as the addInvoice methods are not used by JPA when loading entities.
I tried following the example, http://gwt.google.com/samples/Showcase/Showcase.html#!CwCellTree , and added two ActionCells inside of the CompositeCell with no luck. The ActionCell's onBrowserEvent() does not get triggered.
This simple example works for me. Since you didn't provide any code or further explanation on what exactly you're trying to achieve, I have no idea whether my example is of any help or not.
public void onModuleLoad() {
CellTable<Person> table = new CellTable<Starter.Person>();
List<HasCell<Person, ?>> cells = new LinkedList<HasCell<Person, ?>>();
cells.add(new HasCellImpl("first name", new Delegate<Person>() {
#Override
public void execute(Person object) {
Window.alert(object.getFirstName());
}
}));
cells.add(new HasCellImpl("last name", new Delegate<Starter.Person>() {
#Override
public void execute(Person object) {
Window.alert(object.getLastName());
}
}));
CompositeCell<Person> cell = new CompositeCell<Person>(cells);
table.addColumn(new TextColumn<Starter.Person>() {
#Override
public String getValue(Person object) {
return object.getFirstName() + " " + object.getLastName();
}
}, "name");
table.addColumn(new Column<Person, Person>(cell) {
#Override
public Person getValue(Person object) {
return object;
}
}, "composite");
LinkedList<Person> data = new LinkedList<Starter.Person>();
data.add(new Person("Amy", "Reed"));
data.add(new Person("Tim", "Gardner"));
table.setRowData(data);
RootPanel.get().add(table);
}
private class HasCellImpl implements HasCell<Person, Person> {
private ActionCell<Person> fCell;
public HasCellImpl(String text, Delegate<Person> delegate) {
fCell = new ActionCell<Person>(text, delegate);
}
#Override
public Cell<Person> getCell() {
return fCell;
}
#Override
public FieldUpdater<Person, Person> getFieldUpdater() {
return null;
}
#Override
public Person getValue(Person object) {
return object;
}
}
private class Person {
private String fFirstName;
private String fLastName;
public Person(String first, String last) {
fFirstName = first;
fLastName = last;
}
public String getFirstName() {
return fFirstName;
}
public String getLastName() {
return fLastName;
}
}