Coverage report

| %line | %branch
--- | --- | ---

org.apache.commons.jelly.tags.core.UseBeanTag

70%

99%

1

     /*

2

      * Copyright 2002,2004 The Apache Software Foundation.

3

      *

4

      * Licensed under the Apache License, Version 2.0 (the "License");

5

      * you may not use this file except in compliance with the License.

6

      * You may obtain a copy of the License at

7

      *

8

      *      http://www.apache.org/licenses/LICENSE-2.0

9

      *

10

      * Unless required by applicable law or agreed to in writing, software

11

      * distributed under the License is distributed on an "AS IS" BASIS,

12

      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

13

      * See the License for the specific language governing permissions and

14

      * limitations under the License.

15

      */

16

     package org.apache.commons.jelly.tags.core;

17

18

     import java.lang.reflect.InvocationTargetException;

19

     import java.util.HashMap;

20

     import java.util.HashSet;

21

     import java.util.Iterator;

22

     import java.util.Map;

23

     import java.util.Set;

24

25

     import org.apache.commons.beanutils.BeanUtils;

26

     import org.apache.commons.beanutils.PropertyUtils;

27

     import org.apache.commons.jelly.JellyTagException;

28

     import org.apache.commons.jelly.MapTagSupport;

29

     import org.apache.commons.jelly.MissingAttributeException;

30

     import org.apache.commons.jelly.XMLOutput;

31

     import org.apache.commons.jelly.impl.BeanSource;

32

     import org.apache.commons.jelly.util.ClassLoaderUtils;

33

34

     /**

35

      * A tag which instantiates an instance of the given class

36

      * and then sets the properties on the bean.

37

      * The class can be specified via a {@link java.lang.Class} instance or

38

      * a String which will be used to load the class using either the current

39

      * thread's context class loader or the class loader used to load this

40

      * Jelly library.

41

      *

42

      * This tag can be used it as follows,

43

      * <pre>

44

      * &lt;j:useBean var="person" class="com.acme.Person" name="James" location="${loc}"/&gt;

45

      * &lt;j:useBean var="order" class="${orderClass}" amount="12" price="123.456"/&gt;

46

      * </pre>

47

      *

48

      * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>

49

      * @version $Revision: 155420 $

50

      */

51

     public class UseBeanTag extends MapTagSupport implements BeanSource {

52

53

         /** the current bean instance */

54

         private Object bean;

55

56

         /** the default class to use if no Class is specified */

57

         private Class defaultClass;

58

59

         /**

60

          * a Set of Strings of property names to ignore (remove from the

61

          * Map of attributes before passing to ConvertUtils)

62

          */

63

         private Set ignoreProperties;

64

65

         /**

66

          * If this tag finds an attribute in the XML that's not

67

          * ignored by {@link #ignoreProperties} and isn't a

68

          * bean property, should it throw an exception?

69

          * @see #setIgnoreUnknownProperties(boolean)

70

          */

71

91

         private boolean ignoreUnknownProperties = false;

72

73

74

91

         public UseBeanTag() {

75

91

         }

76

77

0

         public UseBeanTag(Class defaultClass) {

78

0

             this.defaultClass = defaultClass;

79

0

         }

80

81

         // BeanSource interface

82

         //-------------------------------------------------------------------------

83

84

         /**

85

          * @return the bean that has just been created

86

          */

87

         public Object getBean() {

88

13

             return bean;

89

         }

90

91

92

         // Tag interface

93

         //-------------------------------------------------------------------------

94

         public void doTag(XMLOutput output) throws JellyTagException {

95

91

             Map attributes = getAttributes();

96

91

             String var = (String) attributes.get( "var" );

97

91

             Object classObject = attributes.get( "class" );

98

91

             addIgnoreProperty("class");

99

91

             addIgnoreProperty("var");

100

101

             try {

102

                 // this method could return null in derived classes

103

91

                 Class theClass = convertToClass(classObject);

104

105

91

                 bean = newInstance(theClass, attributes, output);

106

91

                 setBeanProperties(bean, attributes);

107

108

                 // invoke body which could result in other properties being set

109

78

                 invokeBody(output);

110

111

78

                 processBean(var, bean);

112

             }

113

0

             catch (ClassNotFoundException e) {

114

0

                 throw new JellyTagException(e);

115

78

             }

116

78

         }

117

118

         // Implementation methods

119

         //-------------------------------------------------------------------------

120

121

         /**

122

          * Allow derived classes to programatically set the bean

123

          */

124

         protected void setBean(Object bean) {

125

0

             this.bean = bean;

126

0

         }

127

128

         /**

129

          * Attempts to convert the given object to a Class instance.

130

          * If the classObject is already a Class it will be returned

131

          * otherwise it will be converted to a String and loaded

132

          * using the default class loading mechanism.

133

          */

134

         protected Class convertToClass(Object classObject)

135

         throws MissingAttributeException, ClassNotFoundException {

136

91

             if (classObject instanceof Class) {

137

0

                 return (Class) classObject;

138

             }

139

91

             else if ( classObject == null ) {

140

0

                 Class theClass = getDefaultClass();

141

0

                 if (theClass == null) {

142

0

                     throw new MissingAttributeException("class");

143

                 }

144

0

                 return theClass;

145

             }

146

             else {

147

91

                 String className = classObject.toString();

148

91

                 return loadClass(className);

149

             }

150

         }

151

152

         /**

153

          * Loads the given class using the default class loading mechanism

154

          * which is to try use the current Thread's context class loader first

155

          * otherise use the class loader which loaded this class.

156

          */

157

         protected Class loadClass(String className) throws ClassNotFoundException {

158

91

             return ClassLoaderUtils.loadClass(className, getClass());

159

         }

160

161

         /**

162

          * Creates a new instance of the given class, which by default will invoke the

163

          * default constructor.

164

          * Derived tags could do something different here.

165

          */

166

         protected Object newInstance(Class theClass, Map attributes, XMLOutput output)

167

         throws JellyTagException {

168

             try {

169

91

                 return theClass.newInstance();

170

0

             } catch (IllegalAccessException e) {

171

0

                 throw new JellyTagException(e.toString());

172

0

             } catch (InstantiationException e) {

173

0

                 throw new JellyTagException(e.toString());

174

             }

175

         }

176

177

         /**

178

          * Sets the properties on the bean. Derived tags could implement some custom

179

          * type conversion etc.

180

          * <p/>

181

          * This method ignores all property names in the Set returned by {@link #getIgnorePropertySet()}.

182

          */

183

         protected void setBeanProperties(Object bean, Map attributes) throws JellyTagException {

184

91

             Map attrsToUse = new HashMap(attributes);

185

91

             attrsToUse.keySet().removeAll(getIgnorePropertySet());

186

187

91

             validateBeanProperties(bean, attrsToUse);

188

189

             try {

190

78

                 BeanUtils.populate(bean, attrsToUse);

191

0

             } catch (IllegalAccessException e) {

192

0

                 throw new JellyTagException("could not set the properties of the bean",e);

193

0

             } catch (InvocationTargetException e) {

194

0

                 throw new JellyTagException("could not set the properties of the bean",e);

195

78

             }

196

78

         }

197

198

         /**

199

          * If {@link #isIgnoreUnknownProperties()} returns true, make sure that

200

          * every non-ignored ({@see #addIgnoreProperty(String)}) property

201

          * matches a writable property on the target bean.

202

          * @param bean the bean to validate

203

          * @param attributes the list of properties to validate

204

          * @throws JellyTagException when a property is not writeable

205

          */

206

         protected void validateBeanProperties(Object bean, Map attributes) throws JellyTagException {

207

91

             if (!isIgnoreUnknownProperties()) {

208

78

                 for (Iterator i=attributes.keySet().iterator();i.hasNext();) {

209

130

                     String attrName = (String)i.next();

210

130

                     if (! PropertyUtils.isWriteable(bean, attrName)) {

211

13

                         throw new JellyTagException("No bean property found: " + attrName);

212

                     }

213

117

                 }

214

             }

215

78

         }

216

217

         /**

218

          * By default this will export the bean using the given variable if it is defined.

219

          * This Strategy method allows derived tags to process the beans in different ways

220

          * such as to register this bean with its parent tag etc.

221

          */

222

         protected void processBean(String var, Object bean) throws JellyTagException {

223

78

             if (var != null) {

224

65

                 context.setVariable(var, bean);

225

65

             }

226

             else {

227

26

                 ArgTag parentArg = (ArgTag)(findAncestorWithClass(ArgTag.class));

228

13

                 if(null != parentArg) {

229

13

                     parentArg.setValue(bean);

230

                 }

231

             }

232

78

         }

233

234

         /**

235

          * Allows derived classes to provide a default bean implementation class

236

          */

237

         protected Class getDefaultClass() {

238

0

             return defaultClass;

239

         }

240

241

         /**

242

          * Adds a name to the Set of property names that will be skipped when setting

243

          * bean properties. In other words, names added here won't be set into the bean

244

          * if they're present in the attribute Map.

245

          * @param name

246

          */

247

         protected void addIgnoreProperty(String name) {

248

195

             getIgnorePropertySet().add(name);

249

195

         }

250

251

         /**

252

          * @return the Set of property names that should be ignored when setting the

253

          * properties of the bean.

254

          */

255

         protected Set getIgnorePropertySet() {

256

286

             if (ignoreProperties == null) {

257

91

                 ignoreProperties = new HashSet();

258

             }

259

260

286

             return ignoreProperties;

261

         }

262

263

         /**

264

          * @see {@link #setIgnoreUnknownProperties(boolean)}

265

          * @return

266

          */

267

         public boolean isIgnoreUnknownProperties() {

268

91

             return ignoreUnknownProperties;

269

         }

270

271

         /**

272

          * If this tag finds an attribute in the XML that's not

273

          * ignored by {@link #ignoreProperties} and isn't a

274

          * bean property, should it throw an exception?

275

          * @param ignoreUnknownProperties Sets {@link #ignoreUnknownProperties}.

276

          */

277

         public void setIgnoreUnknownProperties(boolean ignoreUnknownProps) {

278

13

             this.ignoreUnknownProperties = ignoreUnknownProps;

279

13

         }

280

     }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.