1d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar/*
2d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Copyright (C) 2015 The Android Open Source Project
3d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
4d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * you may not use this file except in compliance with the License.
6d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * You may obtain a copy of the License at
7d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
8d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
10d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Unless required by applicable law or agreed to in writing, software
11d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * See the License for the specific language governing permissions and
14d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * limitations under the License.
15d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar */
16d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
17fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.tool;
18d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
19fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.Expr;
20fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.ExprModel;
21d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.processing.ErrorMessages;
22731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyarimport android.databinding.tool.processing.Scope;
23731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyarimport android.databinding.tool.processing.scopes.LocationScopeProvider;
24fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelAnalyzer;
25fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelClass;
26731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyarimport android.databinding.tool.store.Location;
27fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.store.ResourceBundle;
28fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.store.SetterStore;
29d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.store.SetterStore.BindingGetterCall;
30e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyarimport android.databinding.tool.util.L;
312611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyarimport android.databinding.tool.util.Preconditions;
32d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
33d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.ArrayList;
34e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyarimport java.util.HashMap;
35d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.List;
36e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyarimport java.util.Map;
37d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
38731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyarpublic class BindingTarget implements LocationScopeProvider {
39895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar    List<Binding> mBindings = new ArrayList<Binding>();
40d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    List<InverseBinding> mInverseBindings = new ArrayList<InverseBinding>();
41d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    ExprModel mModel;
4279fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount    ModelClass mResolvedClass;
4334a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount
445bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    // if this target presents itself in multiple layout files with different view types,
455bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    // it receives an interface type and should use it in the getter instead.
46d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    ResourceBundle.BindingTargetBundle mBundle;
473bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar
483bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar    public BindingTarget(ResourceBundle.BindingTargetBundle bundle) {
493bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        mBundle = bundle;
505bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    }
515bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar
525bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    public boolean isUsed() {
533bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        return mBundle.isUsed();
54d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
55d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
56d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void addBinding(String name, Expr expr) {
57d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        if (SetterStore.get(ModelAnalyzer.getInstance()).isTwoWayEventAttribute(name)) {
58d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            L.e(ErrorMessages.TWO_WAY_EVENT_ATTRIBUTE, name);
59d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        }
60d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mBindings.add(new Binding(this, name, expr));
61d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        if (expr.isTwoWay()) {
62d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            try {
63d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                Scope.enter(expr);
64d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                expr.assertIsInvertible();
65d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                final InverseBinding inverseBinding = new InverseBinding(this, name, expr);
66d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                mInverseBindings.add(inverseBinding);
67d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                mBindings.add(new Binding(this, inverseBinding.getEventAttribute(),
68d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                        mModel.twoWayListenerExpr(inverseBinding),
69d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                        inverseBinding.getEventSetter()));
70d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            } finally {
71d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                Scope.exit();
72d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            }
73d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        }
74d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
75d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
765bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    public String getInterfaceType() {
773bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        return mBundle.getInterfaceType() == null ? mBundle.getFullClassName() : mBundle.getInterfaceType();
78d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
79d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
80d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public InverseBinding addInverseBinding(String name, BindingGetterCall call) {
81d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        final InverseBinding inverseBinding = new InverseBinding(this, name, null);
82d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        inverseBinding.setGetterCall(call);
83d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        mInverseBindings.add(inverseBinding);
84d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        mBindings.add(new Binding(this, inverseBinding.getEventAttribute(),
85d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                mModel.twoWayListenerExpr(inverseBinding)));
86d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return inverseBinding;
87d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
88d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
89731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar    @Override
90731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar    public List<Location> provideScopeLocation() {
91731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar        return mBundle.provideScopeLocation();
92731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar    }
93731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar
94d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public String getId() {
953bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        return mBundle.getId();
96d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
97d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
9800da715547ee7d5d38a3b8576090ca427a94daa5George Mount    public String getTag() {
9900da715547ee7d5d38a3b8576090ca427a94daa5George Mount        return mBundle.getTag();
10000da715547ee7d5d38a3b8576090ca427a94daa5George Mount    }
10100da715547ee7d5d38a3b8576090ca427a94daa5George Mount
10200da715547ee7d5d38a3b8576090ca427a94daa5George Mount    public String getOriginalTag() {
10300da715547ee7d5d38a3b8576090ca427a94daa5George Mount        return mBundle.getOriginalTag();
10400da715547ee7d5d38a3b8576090ca427a94daa5George Mount    }
10500da715547ee7d5d38a3b8576090ca427a94daa5George Mount
106d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public String getViewClass() {
1073bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        return mBundle.getFullClassName();
108d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
109d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
11079fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount    public ModelClass getResolvedType() {
111d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mResolvedClass == null) {
112d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            if (mBundle.isBinder()) {
113d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                mResolvedClass = ModelAnalyzer.getInstance().
114d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                        findClass(ModelAnalyzer.VIEW_DATA_BINDING, mModel.getImports());
115d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            } else {
116d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                mResolvedClass = ModelAnalyzer.getInstance().findClass(mBundle.getFullClassName(),
117d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                        mModel.getImports());
118d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            }
119d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
120d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mResolvedClass;
121d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
122d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
1237551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar    public String getIncludedLayout() {
1243bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        return mBundle.getIncludedLayout();
1257551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar    }
1267551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar
1277551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar    public boolean isBinder() {
1283bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        return getIncludedLayout() != null;
1297551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar    }
1307551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar
13100da715547ee7d5d38a3b8576090ca427a94daa5George Mount    public boolean supportsTag() {
13200da715547ee7d5d38a3b8576090ca427a94daa5George Mount        return !SetterStore.get(ModelAnalyzer.getInstance())
13300da715547ee7d5d38a3b8576090ca427a94daa5George Mount                .isUntaggable(mBundle.getFullClassName());
13400da715547ee7d5d38a3b8576090ca427a94daa5George Mount    }
13500da715547ee7d5d38a3b8576090ca427a94daa5George Mount
136d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public List<Binding> getBindings() {
137d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mBindings;
138d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
139d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
140d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public List<InverseBinding> getInverseBindings() {
141d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return mInverseBindings;
142d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
143d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
144d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public ExprModel getModel() {
145d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mModel;
146d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
147d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
148d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void setModel(ExprModel model) {
149d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mModel = model;
150d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
151e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar
152975c05c00dae9193a636c4775df81d8665fc6749George Mount    public void resolveListeners() {
153975c05c00dae9193a636c4775df81d8665fc6749George Mount        for (Binding binding : mBindings) {
154975c05c00dae9193a636c4775df81d8665fc6749George Mount            binding.resolveListeners();
155975c05c00dae9193a636c4775df81d8665fc6749George Mount        }
156975c05c00dae9193a636c4775df81d8665fc6749George Mount    }
157975c05c00dae9193a636c4775df81d8665fc6749George Mount
158d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public void resolveTwoWayExpressions() {
159d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        for (Binding binding : mBindings) {
160d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            binding.resolveTwoWayExpressions();
161d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        }
162d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
163d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
164e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar    /**
165e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar     * Called after BindingTarget is finalized.
166e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar     * <p>
167e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar     * We traverse all bindings and ask SetterStore to figure out if any can be combined.
168e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar     * When N bindings are combined, they are demoted from being a binding expression and a new
169e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar     * ArgList expression is added as the new binding expression that depends on others.
170e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar     */
171e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar    public void resolveMultiSetters() {
172e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        L.d("resolving multi setters for %s", getId());
173e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        final SetterStore setterStore = SetterStore.get(ModelAnalyzer.getInstance());
174e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        final String[] attributes = new String[mBindings.size()];
175e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        final ModelClass[] types = new ModelClass[mBindings.size()];
176e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        for (int i = 0; i < mBindings.size(); i ++) {
177e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar            Binding binding = mBindings.get(i);
178731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar            try {
179731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar                Scope.enter(binding);
180731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar                attributes[i] = binding.getName();
181731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar                types[i] = binding.getExpr().getResolvedType();
182731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar            } finally {
183731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar                Scope.exit();
184731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar            }
185e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        }
186e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        final List<SetterStore.MultiAttributeSetter> multiAttributeSetterCalls = setterStore
187e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar                .getMultiAttributeSetterCalls(attributes, getResolvedType(), types);
188e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        if (multiAttributeSetterCalls.isEmpty()) {
189e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar            return;
190e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        }
191e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        final Map<String, Binding> lookup = new HashMap<String, Binding>();
192e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        for (Binding binding : mBindings) {
193e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar            String name = binding.getName();
194e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar            if (name.startsWith("android:")) {
195e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar                lookup.put(name, binding);
196e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar            } else {
197e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar                int ind = name.indexOf(":");
198e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar                if (ind == -1) {
199e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar                    lookup.put(name, binding);
200e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar                } else {
201e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar                    lookup.put(name.substring(ind + 1), binding);
202e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar                }
203e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar            }
204e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        }
205e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        List<MergedBinding> mergeBindings = new ArrayList<MergedBinding>();
206e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        for (final SetterStore.MultiAttributeSetter setter : multiAttributeSetterCalls) {
207e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar            L.d("resolved %s", setter);
2089784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            final List<Binding> mergedBindings = new ArrayList<Binding>();
2092611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            for (String attribute : setter.attributes) {
2102611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                Binding binding = lookup.get(attribute);
2112611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                Preconditions.checkNotNull(binding, "cannot find binding for %s", attribute);
2122611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                mergedBindings.add(binding);
2132611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            }
2142611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar
215e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar            for (Binding binding : mergedBindings) {
216e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar                binding.getExpr().setBindingExpression(false);
217e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar                mBindings.remove(binding);
218e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar            }
219e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar            MergedBinding mergedBinding = new MergedBinding(getModel(), setter, this,
2202611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                    mergedBindings);
221e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar            mergeBindings.add(mergedBinding);
222e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        }
223e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        for (MergedBinding binding : mergeBindings) {
224e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar            mBindings.add(binding);
225e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        }
226e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar    }
227d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
228