001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.model;
018
019import org.apache.wicket.core.util.lang.PropertyResolver;
020
021/**
022 * A PropertyModel is used to dynamically access a model using a "property expression". See
023 * {@link PropertyResolver} javadoc for allowed property expressions.
024 * <p>
025 * For example, take the following bean:
026 * 
027 * <pre>
028 * public class Person
029 * {
030 *      private String name;
031 * 
032 *      public String getName()
033 *      {
034 *              return name;
035 *      }
036 * 
037 *      public void setName(String name)
038 *      {
039 *              this.name = name;
040 *      }
041 * }
042 * </pre>
043 * 
044 * We could construct a label that dynamically fetches the name property of the given person object
045 * like this:
046 * 
047 * <pre>
048 *     Person person = getSomePerson();
049 *     ...
050 *     add(new Label(&quot;myLabel&quot;, new PropertyModel(person, &quot;name&quot;));
051 * </pre>
052 * 
053 * Where 'myLabel' is the name of the component, and 'name' is the property expression to get the
054 * name property.
055 * </p>
056 * <p>
057 * In the same fashion, we can create form components that work dynamically on the given model
058 * object. For instance, we could create a text field that updates the name property of a person
059 * like this:
060 * 
061 * <pre>
062 *     add(new TextField(&quot;myTextField&quot;, new PropertyModel(person, &quot;name&quot;));
063 * </pre>
064 * 
065 * </p>
066 * <p>
067 * <strong>Note that the property resolver by default provides access to private members and methods. If
068 * guaranteeing encapsulation of the target objects is a big concern, you should consider using an
069 * alternative implementation.</strong>
070 * </p>
071 * 
072 * @see PropertyResolver
073 * @see IModel
074 * @see Model
075 * @see LoadableDetachableModel
076 * 
077 * @author Chris Turner
078 * @author Eelco Hillenius
079 * @author Jonathan Locke
080 * 
081 * @param <T>
082 *            The Model object type
083 */
084public class PropertyModel<T> extends AbstractPropertyModel<T>
085{
086        private static final long serialVersionUID = 1L;
087
088        /** Property expression for property access. */
089        private final String expression;
090
091        /**
092         * Construct with a wrapped (IModel) or unwrapped (non-IModel) object and a property expression
093         * that works on the given model.
094         * 
095         * @param modelObject
096         *            The model object, which may or may not implement IModel
097         * @param expression
098         *            Property expression for property access
099         */
100        public PropertyModel(final Object modelObject, final String expression)
101        {
102                super(modelObject);
103                this.expression = expression;
104        }
105
106        @Override
107        public String toString()
108        {
109                return super.toString() + ":expression=[" + expression + ']';
110        }
111
112        @Override
113        protected String propertyExpression()
114        {
115                return expression;
116        }
117
118        /**
119         * Type-infering factory method
120         * 
121         * @param <Z>
122         *            the of the resolved object from the property
123         * @param parent
124         *            object that contains the property
125         * @param property
126         *            property path
127         * @return {@link PropertyModel} instance
128         */
129        public static <Z> PropertyModel<Z> of(Object parent, String property)
130        {
131                return new PropertyModel<>(parent, property);
132        }
133}