1 /*
2 * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package java.lang.reflect;
27
28 import sun.reflect.ConstructorAccessor;
29 import sun.reflect.Reflection;
30 import sun.reflect.generics.repository.ConstructorRepository;
31 import sun.reflect.generics.factory.CoreReflectionFactory;
32 import sun.reflect.generics.factory.GenericsFactory;
33 import sun.reflect.generics.scope.ConstructorScope;
34 import java.lang.annotation.Annotation;
35 import java.util.Map;
36 import sun.reflect.annotation.AnnotationParser;
37 import java.lang.annotation.AnnotationFormatError;
38 import java.lang.reflect.Modifier;
39
40 /**
41 * {@code Constructor} provides information about, and access to, a single
42 * constructor for a class.
43 *
44 * <p>{@code Constructor} permits widening conversions to occur when matching the
45 * actual parameters to newInstance() with the underlying
46 * constructor's formal parameters, but throws an
47 * {@code IllegalArgumentException} if a narrowing conversion would occur.
48 *
49 * @param <T> the class in which the constructor is declared
50 *
51 * @see Member
52 * @see java.lang.Class
53 * @see java.lang.Class#getConstructors()
54 * @see java.lang.Class#getConstructor(Class[])
55 * @see java.lang.Class#getDeclaredConstructors()
56 *
57 * @author Kenneth Russell
58 * @author Nakul Saraiya
59 */
60 public final
61 class Constructor<T> extends AccessibleObject implements
62 GenericDeclaration,
63 Member {
64
65 private Class<T> clazz;
66 private int slot;
67 private Class[] parameterTypes;
68 private Class[] exceptionTypes;
69 private int modifiers;
70 // Generics and annotations support
71 private transient String signature;
72 // generic info repository; lazily initialized
73 private transient ConstructorRepository genericInfo;
74 private byte[] annotations;
75 private byte[] parameterAnnotations;
76
77 // For non-public members or members in package-private classes,
78 // it is necessary to perform somewhat expensive security checks.
79 // If the security check succeeds for a given class, it will
80 // always succeed (it is not affected by the granting or revoking
81 // of permissions); we speed up the check in the common case by
82 // remembering the last Class for which the check succeeded.
83 private volatile Class securityCheckCache;
84
85 // Modifiers that can be applied to a constructor in source code
86 private static final int LANGUAGE_MODIFIERS =
87 Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
88
89 // Generics infrastructure
90 // Accessor for factory
91 private GenericsFactory getFactory() {
92 // create scope and factory
93 return CoreReflectionFactory.make(this, ConstructorScope.make(this));
94 }
95
96 // Accessor for generic info repository
97 private ConstructorRepository getGenericInfo() {
98 // lazily initialize repository if necessary
99 if (genericInfo == null) {
100 // create and cache generic info repository
101 genericInfo =
102 ConstructorRepository.make(getSignature(),
103 getFactory());
104 }
105 return genericInfo; //return cached repository
106 }
107
108 private volatile ConstructorAccessor constructorAccessor;
109 // For sharing of ConstructorAccessors. This branching structure
110 // is currently only two levels deep (i.e., one root Constructor
111 // and potentially many Constructor objects pointing to it.)
112 private Constructor<T> root;
113
114 /**
115 * Package-private constructor used by ReflectAccess to enable
116 * instantiation of these objects in Java code from the java.lang
117 * package via sun.reflect.LangReflectAccess.
118 */
119 Constructor(Class<T> declaringClass,
120 Class[] parameterTypes,
121 Class[] checkedExceptions,
122 int modifiers,
123 int slot,
124 String signature,
125 byte[] annotations,
126 byte[] parameterAnnotations)
127 {
128 this.clazz = declaringClass;
129 this.parameterTypes = parameterTypes;
130 this.exceptionTypes = checkedExceptions;
131 this.modifiers = modifiers;
132 this.slot = slot;
133 this.signature = signature;
134 this.annotations = annotations;
135 this.parameterAnnotations = parameterAnnotations;
136 }
137
138 /**
139 * Package-private routine (exposed to java.lang.Class via
140 * ReflectAccess) which returns a copy of this Constructor. The copy's
141 * "root" field points to this Constructor.
142 */
143 Constructor<T> copy() {
144 // This routine enables sharing of ConstructorAccessor objects
145 // among Constructor objects which refer to the same underlying
146 // method in the VM. (All of this contortion is only necessary
147 // because of the "accessibility" bit in AccessibleObject,
148 // which implicitly requires that new java.lang.reflect
149 // objects be fabricated for each reflective call on Class
150 // objects.)
151 Constructor<T> res = new Constructor<T>(clazz,
152 parameterTypes,
153 exceptionTypes, modifiers, slot,
154 signature,
155 annotations,
156 parameterAnnotations);
157 res.root = this;
158 // Might as well eagerly propagate this if already present
159 res.constructorAccessor = constructorAccessor;
160 return res;
161 }
162
163 /**
164 * Returns the {@code Class} object representing the class that declares
165 * the constructor represented by this {@code Constructor} object.
166 */
167 public Class<T> getDeclaringClass() {
168 return clazz;
169 }
170
171 /**
172 * Returns the name of this constructor, as a string. This is
173 * always the same as the simple name of the constructor's declaring
174 * class.
175 */
176 public String getName() {
177 return getDeclaringClass().getName();
178 }
179
180 /**
181 * Returns the Java language modifiers for the constructor
182 * represented by this {@code Constructor} object, as an integer. The
183 * {@code Modifier} class should be used to decode the modifiers.
184 *
185 * @see Modifier
186 */
187 public int getModifiers() {
188 return modifiers;
189 }
190
191 /**
192 * Returns an array of {@code TypeVariable} objects that represent the
193 * type variables declared by the generic declaration represented by this
194 * {@code GenericDeclaration} object, in declaration order. Returns an
195 * array of length 0 if the underlying generic declaration declares no type
196 * variables.
197 *
198 * @return an array of {@code TypeVariable} objects that represent
199 * the type variables declared by this generic declaration
200 * @throws GenericSignatureFormatError if the generic
201 * signature of this generic declaration does not conform to
202 * the format specified in the Java Virtual Machine Specification,
203 * 3rd edition
204 * @since 1.5
205 */
206 public TypeVariable<Constructor<T>>[] getTypeParameters() {
207 if (getSignature() != null) {
208 return (TypeVariable<Constructor<T>>[])getGenericInfo().getTypeParameters();
209 } else
210 return (TypeVariable<Constructor<T>>[])new TypeVariable[0];
211 }
212
213
214 /**
215 * Returns an array of {@code Class} objects that represent the formal
216 * parameter types, in declaration order, of the constructor
217 * represented by this {@code Constructor} object. Returns an array of
218 * length 0 if the underlying constructor takes no parameters.
219 *
220 * @return the parameter types for the constructor this object
221 * represents
222 */
223 public Class<?>[] getParameterTypes() {
224 return (Class<?>[]) parameterTypes.clone();
225 }
226
227
228 /**
229 * Returns an array of {@code Type} objects that represent the formal
230 * parameter types, in declaration order, of the method represented by
231 * this {@code Constructor} object. Returns an array of length 0 if the
232 * underlying method takes no parameters.
233 *
234 * <p>If a formal parameter type is a parameterized type,
235 * the {@code Type} object returned for it must accurately reflect
236 * the actual type parameters used in the source code.
237 *
238 * <p>If a formal parameter type is a type variable or a parameterized
239 * type, it is created. Otherwise, it is resolved.
240 *
241 * @return an array of {@code Type}s that represent the formal
242 * parameter types of the underlying method, in declaration order
243 * @throws GenericSignatureFormatError
244 * if the generic method signature does not conform to the format
245 * specified in the Java Virtual Machine Specification, 3rd edition
246 * @throws TypeNotPresentException if any of the parameter
247 * types of the underlying method refers to a non-existent type
248 * declaration
249 * @throws MalformedParameterizedTypeException if any of
250 * the underlying method's parameter types refer to a parameterized
251 * type that cannot be instantiated for any reason
252 * @since 1.5
253 */
254 public Type[] getGenericParameterTypes() {
255 if (getSignature() != null)
256 return getGenericInfo().getParameterTypes();
257 else
258 return getParameterTypes();
259 }
260
261
262 /**
263 * Returns an array of {@code Class} objects that represent the types
264 * of exceptions declared to be thrown by the underlying constructor
265 * represented by this {@code Constructor} object. Returns an array of
266 * length 0 if the constructor declares no exceptions in its {@code throws} clause.
267 *
268 * @return the exception types declared as being thrown by the
269 * constructor this object represents
270 */
271 public Class<?>[] getExceptionTypes() {
272 return (Class<?>[])exceptionTypes.clone();
273 }
274
275
276 /**
277 * Returns an array of {@code Type} objects that represent the
278 * exceptions declared to be thrown by this {@code Constructor} object.
279 * Returns an array of length 0 if the underlying method declares
280 * no exceptions in its {@code throws} clause.
281 *
282 * <p>If an exception type is a parameterized type, the {@code Type}
283 * object returned for it must accurately reflect the actual type
284 * parameters used in the source code.
285 *
286 * <p>If an exception type is a type variable or a parameterized
287 * type, it is created. Otherwise, it is resolved.
288 *
289 * @return an array of Types that represent the exception types
290 * thrown by the underlying method
291 * @throws GenericSignatureFormatError
292 * if the generic method signature does not conform to the format
293 * specified in the Java Virtual Machine Specification, 3rd edition
294 * @throws TypeNotPresentException if the underlying method's
295 * {@code throws} clause refers to a non-existent type declaration
296 * @throws MalformedParameterizedTypeException if
297 * the underlying method's {@code throws} clause refers to a
298 * parameterized type that cannot be instantiated for any reason
299 * @since 1.5
300 */
301 public Type[] getGenericExceptionTypes() {
302 Type[] result;
303 if (getSignature() != null &&
304 ( (result = getGenericInfo().getExceptionTypes()).length > 0 ))
305 return result;
306 else
307 return getExceptionTypes();
308 }
309
310 /**
311 * Compares this {@code Constructor} against the specified object.
312 * Returns true if the objects are the same. Two {@code Constructor} objects are
313 * the same if they were declared by the same class and have the
314 * same formal parameter types.
315 */
316 public boolean equals(Object obj) {
317 if (obj != null && obj instanceof Constructor) {
318 Constructor other = (Constructor)obj;
319 if (getDeclaringClass() == other.getDeclaringClass()) {
320 /* Avoid unnecessary cloning */
321 Class[] params1 = parameterTypes;
322 Class[] params2 = other.parameterTypes;
323 if (params1.length == params2.length) {
324 for (int i = 0; i < params1.length; i++) {
325 if (params1[i] != params2[i])
326 return false;
327 }
328 return true;
329 }
330 }
331 }
332 return false;
333 }
334
335 /**
336 * Returns a hashcode for this {@code Constructor}. The hashcode is
337 * the same as the hashcode for the underlying constructor's
338 * declaring class name.
339 */
340 public int hashCode() {
341 return getDeclaringClass().getName().hashCode();
342 }
343
344 /**
345 * Returns a string describing this {@code Constructor}. The string is
346 * formatted as the constructor access modifiers, if any,
347 * followed by the fully-qualified name of the declaring class,
348 * followed by a parenthesized, comma-separated list of the
349 * constructor's formal parameter types. For example:
350 * <pre>
351 * public java.util.Hashtable(int,float)
352 * </pre>
353 *
354 * <p>The only possible modifiers for constructors are the access
355 * modifiers {@code public}, {@code protected} or
356 * {@code private}. Only one of these may appear, or none if the
357 * constructor has default (package) access.
358 */
359 public String toString() {
360 try {
361 StringBuffer sb = new StringBuffer();
362 int mod = getModifiers() & LANGUAGE_MODIFIERS;
363 if (mod != 0) {
364 sb.append(Modifier.toString(mod) + " ");
365 }
366 sb.append(Field.getTypeName(getDeclaringClass()));
367 sb.append("(");
368 Class[] params = parameterTypes; // avoid clone
369 for (int j = 0; j < params.length; j++) {
370 sb.append(Field.getTypeName(params[j]));
371 if (j < (params.length - 1))
372 sb.append(",");
373 }
374 sb.append(")");
375 Class[] exceptions = exceptionTypes; // avoid clone
376 if (exceptions.length > 0) {
377 sb.append(" throws ");
378 for (int k = 0; k < exceptions.length; k++) {
379 sb.append(exceptions[k].getName());
380 if (k < (exceptions.length - 1))
381 sb.append(",");
382 }
383 }
384 return sb.toString();
385 } catch (Exception e) {
386 return "<" + e + ">";
387 }
388 }
389
390 /**
391 * Returns a string describing this {@code Constructor},
392 * including type parameters. The string is formatted as the
393 * constructor access modifiers, if any, followed by an
394 * angle-bracketed comma separated list of the constructor's type
395 * parameters, if any, followed by the fully-qualified name of the
396 * declaring class, followed by a parenthesized, comma-separated
397 * list of the constructor's generic formal parameter types.
398 *
399 * If this constructor was declared to take a variable number of
400 * arguments, instead of denoting the last parameter as
401 * "<tt><i>Type</i>[]</tt>", it is denoted as
402 * "<tt><i>Type</i>...</tt>".
403 *
404 * A space is used to separate access modifiers from one another
405 * and from the type parameters or return type. If there are no
406 * type parameters, the type parameter list is elided; if the type
407 * parameter list is present, a space separates the list from the
408 * class name. If the constructor is declared to throw
409 * exceptions, the parameter list is followed by a space, followed
410 * by the word "{@code throws}" followed by a
411 * comma-separated list of the thrown exception types.
412 *
413 * <p>The only possible modifiers for constructors are the access
414 * modifiers {@code public}, {@code protected} or
415 * {@code private}. Only one of these may appear, or none if the
416 * constructor has default (package) access.
417 *
418 * @return a string describing this {@code Constructor},
419 * include type parameters
420 *
421 * @since 1.5
422 */
423 public String toGenericString() {
424 try {
425 StringBuilder sb = new StringBuilder();
426 int mod = getModifiers() & LANGUAGE_MODIFIERS;
427 if (mod != 0) {
428 sb.append(Modifier.toString(mod) + " ");
429 }
430 TypeVariable<?>[] typeparms = getTypeParameters();
431 if (typeparms.length > 0) {
432 boolean first = true;
433 sb.append("<");
434 for(TypeVariable<?> typeparm: typeparms) {
435 if (!first)
436 sb.append(",");
437 // Class objects can't occur here; no need to test
438 // and call Class.getName().
439 sb.append(typeparm.toString());
440 first = false;
441 }
442 sb.append("> ");
443 }
444 sb.append(Field.getTypeName(getDeclaringClass()));
445 sb.append("(");
446 Type[] params = getGenericParameterTypes();
447 for (int j = 0; j < params.length; j++) {
448 String param = (params[j] instanceof Class<?>)?
449 Field.getTypeName((Class<?>)params[j]):
450 (params[j].toString());
451 if (isVarArgs() && (j == params.length - 1)) // replace T[] with T...
452 param = param.replaceFirst("\\[\\]$", "...");
453 sb.append(param);
454 if (j < (params.length - 1))
455 sb.append(",");
456 }
457 sb.append(")");
458 Type[] exceptions = getGenericExceptionTypes();
459 if (exceptions.length > 0) {
460 sb.append(" throws ");
461 for (int k = 0; k < exceptions.length; k++) {
462 sb.append((exceptions[k] instanceof Class)?
463 ((Class)exceptions[k]).getName():
464 exceptions[k].toString());
465 if (k < (exceptions.length - 1))
466 sb.append(",");
467 }
468 }
469 return sb.toString();
470 } catch (Exception e) {
471 return "<" + e + ">";
472 }
473 }
474
475 /**
476 * Uses the constructor represented by this {@code Constructor} object to
477 * create and initialize a new instance of the constructor's
478 * declaring class, with the specified initialization parameters.
479 * Individual parameters are automatically unwrapped to match
480 * primitive formal parameters, and both primitive and reference
481 * parameters are subject to method invocation conversions as necessary.
482 *
483 * <p>If the number of formal parameters required by the underlying constructor
484 * is 0, the supplied {@code initargs} array may be of length 0 or null.
485 *
486 * <p>If the constructor's declaring class is an inner class in a
487 * non-static context, the first argument to the constructor needs
488 * to be the enclosing instance; see <i>The Java Language
489 * Specification</i>, section 15.9.3.
490 *
491 * <p>If the required access and argument checks succeed and the
492 * instantiation will proceed, the constructor's declaring class
493 * is initialized if it has not already been initialized.
494 *
495 * <p>If the constructor completes normally, returns the newly
496 * created and initialized instance.
497 *
498 * @param initargs array of objects to be passed as arguments to
499 * the constructor call; values of primitive types are wrapped in
500 * a wrapper object of the appropriate type (e.g. a {@code float}
501 * in a {@link java.lang.Float Float})
502 *
503 * @return a new object created by calling the constructor
504 * this object represents
505 *
506 * @exception IllegalAccessException if this {@code Constructor} object
507 * enforces Java language access control and the underlying
508 * constructor is inaccessible.
509 * @exception IllegalArgumentException if the number of actual
510 * and formal parameters differ; if an unwrapping
511 * conversion for primitive arguments fails; or if,
512 * after possible unwrapping, a parameter value
513 * cannot be converted to the corresponding formal
514 * parameter type by a method invocation conversion; if
515 * this constructor pertains to an enum type.
516 * @exception InstantiationException if the class that declares the
517 * underlying constructor represents an abstract class.
518 * @exception InvocationTargetException if the underlying constructor
519 * throws an exception.
520 * @exception ExceptionInInitializerError if the initialization provoked
521 * by this method fails.
522 */
523 public T newInstance(Object ... initargs)
524 throws InstantiationException, IllegalAccessException,
525 IllegalArgumentException, InvocationTargetException
526 {
527 if (!override) {
528 if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
529 Class caller = Reflection.getCallerClass(2);
530 if (securityCheckCache != caller) {
531 Reflection.ensureMemberAccess(caller, clazz, null, modifiers);
532 securityCheckCache = caller;
533 }
534 }
535 }
536 if ((clazz.getModifiers() & Modifier.ENUM) != 0)
537 throw new IllegalArgumentException("Cannot reflectively create enum objects");
538 if (constructorAccessor == null) acquireConstructorAccessor();
539 return (T) constructorAccessor.newInstance(initargs);
540 }
541
542 /**
543 * Returns {@code true} if this constructor was declared to take
544 * a variable number of arguments; returns {@code false}
545 * otherwise.
546 *
547 * @return {@code true} if an only if this constructor was declared to
548 * take a variable number of arguments.
549 * @since 1.5
550 */
551 public boolean isVarArgs() {
552 return (getModifiers() & Modifier.VARARGS) != 0;
553 }
554
555 /**
556 * Returns {@code true} if this constructor is a synthetic
557 * constructor; returns {@code false} otherwise.
558 *
559 * @return true if and only if this constructor is a synthetic
560 * constructor as defined by the Java Language Specification.
561 * @since 1.5
562 */
563 public boolean isSynthetic() {
564 return Modifier.isSynthetic(getModifiers());
565 }
566
567 // NOTE that there is no synchronization used here. It is correct
568 // (though not efficient) to generate more than one
569 // ConstructorAccessor for a given Constructor. However, avoiding
570 // synchronization will probably make the implementation more
571 // scalable.
572 private void acquireConstructorAccessor() {
573 // First check to see if one has been created yet, and take it
574 // if so.
575 ConstructorAccessor tmp = null;
576 if (root != null) tmp = root.getConstructorAccessor();
577 if (tmp != null) {
578 constructorAccessor = tmp;
579 return;
580 }
581 // Otherwise fabricate one and propagate it up to the root
582 tmp = reflectionFactory.newConstructorAccessor(this);
583 setConstructorAccessor(tmp);
584 }
585
586 // Returns ConstructorAccessor for this Constructor object, not
587 // looking up the chain to the root
588 ConstructorAccessor getConstructorAccessor() {
589 return constructorAccessor;
590 }
591
592 // Sets the ConstructorAccessor for this Constructor object and
593 // (recursively) its root
594 void setConstructorAccessor(ConstructorAccessor accessor) {
595 constructorAccessor = accessor;
596 // Propagate up
597 if (root != null) {
598 root.setConstructorAccessor(accessor);
599 }
600 }
601
602 int getSlot() {
603 return slot;
604 }
605
606 String getSignature() {
607 return signature;
608 }
609
610 byte[] getRawAnnotations() {
611 return annotations;
612 }
613
614 byte[] getRawParameterAnnotations() {
615 return parameterAnnotations;
616 }
617
618 /**
619 * @throws NullPointerException {@inheritDoc}
620 * @since 1.5
621 */
622 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
623 if (annotationClass == null)
624 throw new NullPointerException();
625
626 return (T) declaredAnnotations().get(annotationClass);
627 }
628
629 private static final Annotation[] EMPTY_ANNOTATION_ARRAY=new Annotation[0];
630
631 /**
632 * @since 1.5
633 */
634 public Annotation[] getDeclaredAnnotations() {
635 return declaredAnnotations().values().toArray(EMPTY_ANNOTATION_ARRAY);
636 }
637
638 private transient Map<Class, Annotation> declaredAnnotations;
639
640 private synchronized Map<Class, Annotation> declaredAnnotations() {
641 if (declaredAnnotations == null) {
642 declaredAnnotations = AnnotationParser.parseAnnotations(
643 annotations, sun.misc.SharedSecrets.getJavaLangAccess().
644 getConstantPool(getDeclaringClass()),
645 getDeclaringClass());
646 }
647 return declaredAnnotations;
648 }
649
650 /**
651 * Returns an array of arrays that represent the annotations on the formal
652 * parameters, in declaration order, of the method represented by
653 * this {@code Constructor} object. (Returns an array of length zero if the
654 * underlying method is parameterless. If the method has one or more
655 * parameters, a nested array of length zero is returned for each parameter
656 * with no annotations.) The annotation objects contained in the returned
657 * arrays are serializable. The caller of this method is free to modify
658 * the returned arrays; it will have no effect on the arrays returned to
659 * other callers.
660 *
661 * @return an array of arrays that represent the annotations on the formal
662 * parameters, in declaration order, of the method represented by this
663 * Constructor object
664 * @since 1.5
665 */
666 public Annotation[][] getParameterAnnotations() {
667 int numParameters = parameterTypes.length;
668 if (parameterAnnotations == null)
669 return new Annotation[numParameters][0];
670
671 Annotation[][] result = AnnotationParser.parseParameterAnnotations(
672 parameterAnnotations,
673 sun.misc.SharedSecrets.getJavaLangAccess().
674 getConstantPool(getDeclaringClass()),
675 getDeclaringClass());
676 if (result.length != numParameters) {
677 Class<?> declaringClass = getDeclaringClass();
678 if (declaringClass.isEnum() ||
679 declaringClass.isAnonymousClass() ||
680 declaringClass.isLocalClass() )
681 ; // Can't do reliable parameter counting
682 else {
683 if (!declaringClass.isMemberClass() || // top-level
684 // Check for the enclosing instance parameter for
685 // non-static member classes
686 (declaringClass.isMemberClass() &&
687 ((declaringClass.getModifiers() & Modifier.STATIC) == 0) &&
688 result.length + 1 != numParameters) ) {
689 throw new AnnotationFormatError(
690 "Parameter annotations don't match number of parameters");
691 }
692 }
693 }
694 return result;
695 }
696 }