[[view-model-instantiation]]
= View Model Instantiation

:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR  CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
:page-partial:

The xref:refguide:applib:index/services/factory/FactoryService.adoc[FactoryService] service
covers all use-cases for programmatic view model creation and takes care,
that all injection points are resolved for the resulting view model instance.

.Simple Case (using the public no-arg constructor)
[source,java]
----
CustomerViewModel viewModel = factoryService.viewModel(CustomerViewModel.class);
----

.Advanced Case (using a custom constructor)
[source,java]
----
CustomerViewModel viewModel = factoryService.viewModel(new CustomerViewModel("Joe", "Bloggs"));
----

== TODO outdated docs (likely to just be removed) ...

WARNING: TODO - v2 - don't know if this is still valid or not.
If it is, then we should probably remove FactoryService#create(...) for view models completely.

With view models, some care must be taken in how they are instantiated.
Specifically, it's important that the framework doesn't "know" about the view model until its state is "sufficiently" populated to distinguish from other view models.

In practical terms, this means that view models should be instantiated using a constructor, and then injecting services (if required) using the xref:refguide:applib:index/services/registry/ServiceRegistry.adoc[ServiceRegistry] service:

[source,java]
----
CustomerViewModel viewModel = new CustomerViewModel("Joe", "Bloggs");
serviceInjector.injectServicesInto(viewModel);
----

What will most likely *fail* is to use the xref:refguide:applib:index/services/factory/FactoryService.adoc[FactoryService]:


[source,java]
----
// DON'T DO THIS WITH VIEW MODELS
CustomerViewModel viewModel = factoryService.instantiate(CustomerViewModel.class);

viewModel.setFirstName("Joe");
viewModel.setLastName("Bloggs");
serviceInjector.injectServicesInto(viewModel);
----

That's because the internal "OID" identifier that the framework creates to handle this view model will be incomplete.
Although the framework can handle changes to the OID (when the corresponding view model's state changes) once created, this isn't the case during initial instantiation process.


== Example

To explain further, here's an implementation using `FactoryService` that fails:

[source,java]
----
@XmlRootElement(name = "yearSummary")
@XmlType( propOrder = { /* ... */ } )
@XmlAccessorType(XmlAccessType.FIELD)
public class YearSummary {                                                  // <1>
    ...
    @XmlTransient
    @CollectionLayout(defaultView = "table")
    public List<OfficeOptionViewModel> getAmountsPerOffice() {
        List<OfficeOptionViewModel> amountsPerOffice = new ArrayList<>();

        OfficeOptionViewModel office1 =                                     // <2>
            factoryService.viewModel(OfficeOptionViewModel.class);
        office1.setOffice("Amsterdam");                                     // <3>
        office1.setAmount(200);
        amountsPerOffice.add(office1);

        OfficeOptionViewModel office2 =                                     // <2>
            factoryService.viewModel(OfficeOptionViewModel.class);
        office2.setOffice("London");                                        // <3>
        office2.setAmount(100);
        amountsPerOffice.add(office2);

        return amountsPerOffice;
    }
}
----
<1> Parent view model
<2> Using `FactoryService`, incorrectly.
<3> Hard-coded just for demo purposes

This collection, is, confusing, rendered as:

image::hints-and-tips/view-model-fail.png[width="800px"]

Even though the `amountsPerOffice` collection of view models is correctly populated, the framework/viewer maps these to their corresponding OIDs before they are rendered.
Because the "Amsterdam" pojo and "London" pojo each mapped to the same OID, when fetching out the results the viewer obtains the London pojo both times.

The following implementation, on the other hand, succeeds:



[source,java]
----
@XmlRootElement(name = "yearSummary")
@XmlType( propOrder = { /* ... */ } )
@XmlAccessorType(XmlAccessType.FIELD)
public class YearSummary {
    ...
    @XmlTransient
    @CollectionLayout(defaultView = "table")
    public List<OfficeOptionViewModel> getAmountsPerOffice() {
        List<OfficeOptionViewModel> amountsPerOffice = new ArrayList<>();

		OfficeOptionViewModel office1 = new OfficeOptionViewModel("Amsterdam", 200);    // <1>
		serviceInjector.injectServicesInto(office1);
		amountsPerOffice.add(office1);

		OfficeOptionViewModel office2 = new OfficeOptionViewModel("London", 100);       // <1>
		serviceInjector.injectServicesInto(office2);
		amountsPerOffice.add(office2);

        return amountsPerOffice;
    }
}
----
<1> Just instantiate with constructor.
The framework "sees" the domain object when services are injected into it.

As can be seen, this renders just fine:

image::hints-and-tips/view-model-success.png[width="800px"]


To complicate matters a little, note though that following "incorrect" implementation using `FactoryService` does also work correctly:

[source,java]
----
@XmlRootElement(name = "yearSummary")
@XmlType( propOrder = { ..., "amountsPerOffice" } )                     // <1>
@XmlAccessorType(XmlAccessType.FIELD)
public class YearSummary {
	...

    void init() {
        amountsPerOffice = calculateAmountsPerOffice();
    }

    @XmlElementWrapper
    @XmlElement(name = "officeOption")
    @CollectionLayout(defaultView = "table")
    @Getter @Setter
    private List<OfficeOptionViewModel> amountsPerOffice = Lists.newArrayList();

	@XmlTransient
    @CollectionLayout(defaultView = "table")
    public List<OfficeOptionViewModel> calculateAmountsPerOffice() {
        List<OfficeOptionViewModel> amountsPerOffice = new ArrayList<>();

		OfficeOptionViewModel office1 = factoryService.viewModel(OfficeOptionViewModel.class);
		office1.setOffice("Amsterdam");
		office1.setAmount(200);

		amountsPerOffice.add(office1);

		OfficeOptionViewModel office2 = factoryService.viewModel(OfficeOptionViewModel.class);
		office2.setOffice("London");
		office2.setAmount(100);

		amountsPerOffice.add(office2);

        return amountsPerOffice;
    }
}
----
<1> "amountsPerOffice" is part of the state of the parent view model

In this case the `amountsPerOffice` collection is part of the state of the parent view model and so in this particular case everything works with either `FactoryService#create(...)` or using `ServiceRegistry`.

