1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one or more
3
+ * contributor license agreements. See the NOTICE file distributed with
4
+ * this work for additional information regarding copyright ownership.
5
+ * The ASF licenses this file to You under the Apache License, Version 2.0
6
+ * (the "License"); you may not use this file except in compliance with
7
+ * the License. You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ package io .microsphere .beans ;
19
+
20
+ import io .microsphere .annotation .Immutable ;
21
+ import io .microsphere .annotation .Nonnull ;
22
+
23
+ import java .beans .BeanInfo ;
24
+ import java .beans .Introspector ;
25
+ import java .beans .PropertyDescriptor ;
26
+ import java .util .Collection ;
27
+ import java .util .Map ;
28
+ import java .util .Objects ;
29
+
30
+ import static io .microsphere .collection .MapUtils .newFixedHashMap ;
31
+ import static io .microsphere .lang .function .ThrowableSupplier .execute ;
32
+ import static io .microsphere .util .ClassUtils .getTypeName ;
33
+ import static io .microsphere .util .StringUtils .uncapitalize ;
34
+ import static java .util .Collections .unmodifiableMap ;
35
+
36
+ /**
37
+ * The metadata class of Bean, which is used to represent a Java Bean.
38
+ *
39
+ * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
40
+ * @see BeanInfo
41
+ * @see PropertyDescriptor
42
+ * @since 1.0.0
43
+ */
44
+ public class BeanMetadata {
45
+
46
+ private final Class <?> beanClass ;
47
+
48
+ private final BeanInfo beanInfo ;
49
+
50
+ private final Map <String , PropertyDescriptor > propertyDescriptorsMap ;
51
+
52
+ protected BeanMetadata (@ Nonnull Class <?> beanClass ) {
53
+ this (execute (() -> Introspector .getBeanInfo (beanClass , Object .class )));
54
+ }
55
+
56
+ protected BeanMetadata (BeanInfo beanInfo ) {
57
+ this .beanInfo = beanInfo ;
58
+ this .propertyDescriptorsMap = buildPropertyDescriptorsMap (beanInfo );
59
+ this .beanClass = beanInfo .getBeanDescriptor ().getBeanClass ();
60
+ }
61
+
62
+ @ Nonnull
63
+ @ Immutable
64
+ static Map <String , PropertyDescriptor > buildPropertyDescriptorsMap (BeanInfo beanInfo ) {
65
+ PropertyDescriptor [] propertyDescriptors = beanInfo .getPropertyDescriptors ();
66
+ int length = propertyDescriptors .length ;
67
+ Map <String , PropertyDescriptor > propertyDescriptorsMap = newFixedHashMap (length );
68
+ for (int i = 0 ; i < length ; i ++) {
69
+ PropertyDescriptor propertyDescriptor = propertyDescriptors [i ];
70
+ String propertyName = uncapitalize (propertyDescriptor .getName ());
71
+ propertyDescriptorsMap .put (propertyName , propertyDescriptor );
72
+ }
73
+ return unmodifiableMap (propertyDescriptorsMap );
74
+ }
75
+
76
+ public BeanInfo getBeanInfo () {
77
+ return this .beanInfo ;
78
+ }
79
+
80
+ @ Nonnull
81
+ @ Immutable
82
+ public Collection <PropertyDescriptor > getPropertyDescriptors () {
83
+ return this .propertyDescriptorsMap .values ();
84
+ }
85
+
86
+ /**
87
+ * Get the {@link PropertyDescriptor} by property name
88
+ *
89
+ * @param propertyName the property name, which is usually the uncapitalized name of the property
90
+ * (e.g., "propertyName" for a property named "PropertyName")
91
+ * @return the {@link PropertyDescriptor} if found, otherwise {@code null}
92
+ */
93
+ public PropertyDescriptor getPropertyDescriptor (String propertyName ) {
94
+ return this .propertyDescriptorsMap .get (propertyName );
95
+ }
96
+
97
+ @ Nonnull
98
+ @ Immutable
99
+ public Map <String , PropertyDescriptor > getPropertyDescriptorsMap () {
100
+ return this .propertyDescriptorsMap ;
101
+ }
102
+
103
+ public Class <?> getBeanClass () {
104
+ return this .beanClass ;
105
+ }
106
+
107
+ @ Override
108
+ public final boolean equals (Object o ) {
109
+ if (!(o instanceof BeanMetadata )) return false ;
110
+
111
+ BeanMetadata that = (BeanMetadata ) o ;
112
+ return Objects .equals (getBeanClass (), that .getBeanClass ());
113
+ }
114
+
115
+ @ Override
116
+ public int hashCode () {
117
+ return Objects .hashCode (getBeanClass ());
118
+ }
119
+
120
+ @ Override
121
+ public String toString () {
122
+ return "BeanMetadata{" + "beanClass='" + getTypeName (this .beanClass ) + "'}" ;
123
+ }
124
+
125
+
126
+ /**
127
+ * Create a {@link BeanMetadata} instance from the specified bean class.
128
+ *
129
+ * <h3>Example Usage</h3>
130
+ * <pre>{@code
131
+ * // Example 1: Create BeanMetadata for a simple Java Bean
132
+ * BeanMetadata metadata = BeanMetadata.of(Person.class);
133
+ *
134
+ * // Example 2: Create BeanMetadata for a complex Bean
135
+ * BeanMetadata metadata = BeanMetadata.of(Company.class);
136
+ * }</pre>
137
+ *
138
+ * @param beanClass the bean class must not be {@code null}
139
+ * @return a {@link BeanMetadata} instance
140
+ * @throws RuntimeException if the {@link BeanInfo} cannot be obtained from the specified bean class
141
+ * @see Introspector#getBeanInfo(Class, Class)
142
+ */
143
+ public static BeanMetadata of (@ Nonnull Class <?> beanClass ) throws RuntimeException {
144
+ return new BeanMetadata (beanClass );
145
+ }
146
+
147
+ }
0 commit comments