35 | * // Static import all reflection methods to decrease verbosity
36 | * import static org.joor.Reflect.*;
37 | *
38 | * // Wrap an Object / Class / class name with the on() method:
39 | * on("java.lang.String")
40 | * // Invoke constructors using the create() method:
41 | * .create("Hello World")
42 | * // Invoke methods using the call() method:
43 | * .call("toString")
44 | * // Retrieve the wrapped object
45 | *
46 | * @author Lukas Eder
47 | * @author Irek Matysiewicz
48 | * @author Thomas Darimont
49 | */
50 | public class Reflect {
51 |
52 | // ---------------------------------------------------------------------
53 | // Static API used as entrance points to the fluent API
54 | // ---------------------------------------------------------------------
55 |
56 | /**
57 | * Wrap a class name.
58 | *
59 | * This is the same as calling on(Class.forName(name))
60 | *
61 | * @param name A fully qualified class name
62 | * @return A wrapped class object, to be used for further reflection.
63 | * @throws ReflectException If any reflection exception occurred.
64 | * @see #on(Class)
65 | */
66 | public static Reflect on(String name) throws ReflectException {
67 | return on(forName(name));
68 | }
69 |
70 | /**
71 | * Wrap a class name, loading it via a given class loader.
72 | *
73 | * This is the same as calling
74 | * on(Class.forName(name, classLoader))
75 | *
76 | * @param name A fully qualified class name.
77 | * @param classLoader The class loader in whose context the class should be
78 | * loaded.
79 | * @return A wrapped class object, to be used for further reflection.
80 | * @throws ReflectException If any reflection exception occurred.
81 | * @see #on(Class)
82 | */
83 | public static Reflect on(String name, ClassLoader classLoader) throws ReflectException {
84 | return on(forName(name, classLoader));
85 | }
86 |
87 | /**
88 | * Wrap a class.
89 | *
90 | * Use this when you want to access static fields and methods on a
91 | * {@link Class} object, or as a basis for constructing objects of that
92 | * class using {@link #create(Object...)}
93 | *
94 | * @param clazz The class to be wrapped
95 | * @return A wrapped class object, to be used for further reflection.
96 | */
97 | public static Reflect on(Class> clazz) {
98 | return new Reflect(clazz);
99 | }
100 |
101 | /**
102 | * Wrap an object.
103 | *
104 | * Use this when you want to access instance fields and methods on any
105 | * {@link Object}
106 | *
107 | * @param object The object to be wrapped
108 | * @return A wrapped object, to be used for further reflection.
109 | */
110 | public static Reflect on(Object object) {
111 | return new Reflect(object);
112 | }
113 |
114 | /**
115 | * Conveniently render an {@link AccessibleObject} accessible.
116 | *
117 | * To prevent {@link SecurityException}, this is only done if the argument
118 | * object and its declaring class are non-public.
119 | *
120 | * @param accessible The object to render accessible
121 | * @return The argument object rendered accessible
122 | */
123 | public static T accessible(T accessible) {
124 | if (accessible == null) {
125 | return null;
126 | }
127 |
128 | if (accessible instanceof Member) {
129 | Member member = (Member) accessible;
130 |
131 | if (Modifier.isPublic(member.getModifiers()) &&
132 | Modifier.isPublic(member.getDeclaringClass().getModifiers())) {
133 |
134 | return accessible;
135 | }
136 | }
137 |
138 | // [jOOQ #3392] The accessible flag is set to false by default, also for public members.
139 | if (!accessible.isAccessible()) {
140 | accessible.setAccessible(true);
141 | }
142 |
143 | return accessible;
144 | }
145 |
146 | // ---------------------------------------------------------------------
147 | // Members
148 | // ---------------------------------------------------------------------
149 |
150 | /* [java-8] */
151 | private static final Constructor CACHED_LOOKUP_CONSTRUCTOR;
152 |
153 | static {
154 | try {
155 | CACHED_LOOKUP_CONSTRUCTOR = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class);
156 |
157 | if (!CACHED_LOOKUP_CONSTRUCTOR.isAccessible())
158 | CACHED_LOOKUP_CONSTRUCTOR.setAccessible(true);
159 | }
160 | catch (Exception e) {
161 | throw new IllegalStateException(e);
162 | }
163 | }
164 | /* [/java-8] */
165 |
166 | /**
167 | * The wrapped object
168 | */
169 | private final Object object;
170 |
171 | /**
172 | * A flag indicating whether the wrapped object is a {@link Class} (for
173 | * accessing static fields and methods), or any other type of {@link Object}
174 | * (for accessing instance fields and methods).
175 | */
176 | private final boolean isClass;
177 |
178 | // ---------------------------------------------------------------------
179 | // Constructors
180 | // ---------------------------------------------------------------------
181 |
182 | private Reflect(Class> type) {
183 | this.object = type;
184 | this.isClass = true;
185 | }
186 |
187 | private Reflect(Object object) {
188 | this.object = object;
189 | this.isClass = false;
190 | }
191 |
192 | // ---------------------------------------------------------------------
193 | // Fluent Reflection API
194 | // ---------------------------------------------------------------------
195 |
196 | /**
197 | * Get the wrapped object
198 | *
199 | * @param A convenience generic parameter for automatic unsafe casting
200 | */
201 | @SuppressWarnings("unchecked")
202 | public T get() {
203 | return (T) object;
204 | }
205 |
206 | /**
207 | * Set a field value.
208 | *
209 | * This is roughly equivalent to {@link Field#set(Object, Object)}. If the
210 | * wrapped object is a {@link Class}, then this will set a value to a static
211 | * member field. If the wrapped object is any other {@link Object}, then
212 | * this will set a value to an instance member field.
213 | *
214 | * This method is also capable of setting the value of (static) final
215 | * fields. This may be convenient in situations where no
216 | * {@link SecurityManager} is expected to prevent this, but do note that
217 | * (especially static) final fields may already have been inlined by the
218 | * javac and/or JIT and relevant code deleted from the runtime verison of
219 | * your program, so setting these fields might not have any effect on your
220 | * execution.
221 | *
222 | * For restrictions of usage regarding setting values on final fields check:
223 | * http://stackoverflow.com/questions/3301635/change-private-static-final-field-using-java-reflection
225 | * ... and http://pveentjer.blogspot.co.at/2017/01/final-static-boolean-jit.html
227 | *
228 | * @param name The field name
229 | * @param value The new field value
230 | * @return The same wrapped object, to be used for further reflection.
231 | * @throws ReflectException If any reflection exception occurred.
232 | */
233 | public Reflect set(String name, Object value) throws ReflectException {
234 | try {
235 | Field field = field0(name);
236 | if ((field.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {
237 | Field modifiersField = Field.class.getDeclaredField("modifiers");
238 | modifiersField.setAccessible(true);
239 | modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
240 | }
241 | field.set(object, unwrap(value));
242 | return this;
243 | }
244 | catch (Exception e) {
245 | throw new ReflectException(e);
246 | }
247 | }
248 |
249 | /**
250 | * Get a field value.
251 | *
252 | * This is roughly equivalent to {@link Field#get(Object)}. If the wrapped
253 | * object is a {@link Class}, then this will get a value from a static
254 | * member field. If the wrapped object is any other {@link Object}, then
255 | * this will get a value from an instance member field.
256 | *
257 | * If you want to "navigate" to a wrapped version of the field, use
258 | * {@link #field(String)} instead.
259 | *
260 | * @param name The field name
261 | * @return The field value
262 | * @throws ReflectException If any reflection exception occurred.
263 | * @see #field(String)
264 | */
265 | public T get(String name) throws ReflectException {
266 | return field(name).get();
267 | }
268 |
269 | /**
270 | * Get a wrapped field.
271 | *
272 | * This is roughly equivalent to {@link Field#get(Object)}. If the wrapped
273 | * object is a {@link Class}, then this will wrap a static member field. If
274 | * the wrapped object is any other {@link Object}, then this wrap an
275 | * instance member field.
276 | *
277 | * @param name The field name
278 | * @return The wrapped field
279 | * @throws ReflectException If any reflection exception occurred.
280 | */
281 | public Reflect field(String name) throws ReflectException {
282 | try {
283 | Field field = field0(name);
284 | return on(field.get(object));
285 | }
286 | catch (Exception e) {
287 | throw new ReflectException(e);
288 | }
289 | }
290 |
291 | private Field field0(String name) throws ReflectException {
292 | Class> type = type();
293 |
294 | // Try getting a public field
295 | try {
296 | return accessible(type.getField(name));
297 | }
298 |
299 | // Try again, getting a non-public field
300 | catch (NoSuchFieldException e) {
301 | do {
302 | try {
303 | return accessible(type.getDeclaredField(name));
304 | }
305 | catch (NoSuchFieldException ignore) {}
306 |
307 | type = type.getSuperclass();
308 | }
309 | while (type != null);
310 |
311 | throw new ReflectException(e);
312 | }
313 | }
314 |
315 | /**
316 | * Get a Map containing field names and wrapped values for the fields'
317 | * values.
318 | *
319 | * If the wrapped object is a {@link Class}, then this will return static
320 | * fields. If the wrapped object is any other {@link Object}, then this will
321 | * return instance fields.
322 | *
323 | * These two calls are equivalent
324 | * on(object).field("myField");
325 | * on(object).fields().get("myField");
326 | *
327 | *
328 | * @return A map containing field names and wrapped values.
329 | */
330 | public Map fields() {
331 | Map result = new LinkedHashMap();
332 | Class> type = type();
333 |
334 | do {
335 | for (Field field : type.getDeclaredFields()) {
336 | if (!isClass ^ Modifier.isStatic(field.getModifiers())) {
337 | String name = field.getName();
338 |
339 | if (!result.containsKey(name))
340 | result.put(name, field(name));
341 | }
342 | }
343 |
344 | type = type.getSuperclass();
345 | }
346 | while (type != null);
347 |
348 | return result;
349 | }
350 |
351 | /**
352 | * Call a method by its name.
353 | *
354 | * This is a convenience method for calling
355 | * call(name, new Object[0])
356 | *
357 | * @param name The method name
358 | * @return The wrapped method result or the same wrapped object if the
359 | * method returns void
, to be used for further
360 | * reflection.
361 | * @throws ReflectException If any reflection exception occurred.
362 | * @see #call(String, Object...)
363 | */
364 | public Reflect call(String name) throws ReflectException {
365 | return call(name, new Object[0]);
366 | }
367 |
368 | /**
369 | * Call a method by its name.
370 | *
371 | * This is roughly equivalent to {@link Method#invoke(Object, Object...)}.
372 | * If the wrapped object is a {@link Class}, then this will invoke a static
373 | * method. If the wrapped object is any other {@link Object}, then this will
374 | * invoke an instance method.
375 | *
376 | * Just like {@link Method#invoke(Object, Object...)}, this will try to wrap
377 | * primitive types or unwrap primitive type wrappers if applicable. If
378 | * several methods are applicable, by that rule, the first one encountered
379 | * is called. i.e. when calling
380 | * on(...).call("method", 1, 1);
381 | *
The first of the following methods will be called:
382 | *
383 | * public void method(int param1, Integer param2);
384 | * public void method(Integer param1, int param2);
385 | * public void method(Number param1, Number param2);
386 | * public void method(Number param1, Object param2);
387 | * public void method(int param1, Object param2);
388 | *
389 | *
390 | * The best matching method is searched for with the following strategy:
391 | *
392 | * - public method with exact signature match in class hierarchy
393 | * - non-public method with exact signature match on declaring class
394 | * - public method with similar signature in class hierarchy
395 | * - non-public method with similar signature on declaring class
396 | *
397 | *
398 | * @param name The method name
399 | * @param args The method arguments
400 | * @return The wrapped method result or the same wrapped object if the
401 | * method returns void
, to be used for further
402 | * reflection.
403 | * @throws ReflectException If any reflection exception occurred.
404 | */
405 | public Reflect call(String name, Object... args) throws ReflectException {
406 | Class>[] types = types(args);
407 |
408 | // Try invoking the "canonical" method, i.e. the one with exact
409 | // matching argument types
410 | try {
411 | Method method = exactMethod(name, types);
412 | return on(method, object, args);
413 | }
414 |
415 | // If there is no exact match, try to find a method that has a "similar"
416 | // signature if primitive argument types are converted to their wrappers
417 | catch (NoSuchMethodException e) {
418 | try {
419 | Method method = similarMethod(name, types);
420 | return on(method, object, args);
421 | } catch (NoSuchMethodException e1) {
422 | throw new ReflectException(e1);
423 | }
424 | }
425 | }
426 |
427 | /**
428 | * Searches a method with the exact same signature as desired.
429 | *
430 | * If a public method is found in the class hierarchy, this method is returned.
431 | * Otherwise a private method with the exact same signature is returned.
432 | * If no exact match could be found, we let the {@code NoSuchMethodException} pass through.
433 | */
434 | private Method exactMethod(String name, Class>[] types) throws NoSuchMethodException {
435 | Class> type = type();
436 |
437 | // first priority: find a public method with exact signature match in class hierarchy
438 | try {
439 | return type.getMethod(name, types);
440 | }
441 |
442 | // second priority: find a private method with exact signature match on declaring class
443 | catch (NoSuchMethodException e) {
444 | do {
445 | try {
446 | return type.getDeclaredMethod(name, types);
447 | }
448 | catch (NoSuchMethodException ignore) {}
449 |
450 | type = type.getSuperclass();
451 | }
452 | while (type != null);
453 |
454 | throw new NoSuchMethodException();
455 | }
456 | }
457 |
458 | /**
459 | * Searches a method with a similar signature as desired using
460 | * {@link #isSimilarSignature(java.lang.reflect.Method, String, Class[])}.
461 | *
462 | * First public methods are searched in the class hierarchy, then private
463 | * methods on the declaring class. If a method could be found, it is
464 | * returned, otherwise a {@code NoSuchMethodException} is thrown.
465 | */
466 | private Method similarMethod(String name, Class>[] types) throws NoSuchMethodException {
467 | Class> type = type();
468 |
469 | // first priority: find a public method with a "similar" signature in class hierarchy
470 | // similar interpreted in when primitive argument types are converted to their wrappers
471 | for (Method method : type.getMethods()) {
472 | if (isSimilarSignature(method, name, types)) {
473 | return method;
474 | }
475 | }
476 |
477 | // second priority: find a non-public method with a "similar" signature on declaring class
478 | do {
479 | for (Method method : type.getDeclaredMethods()) {
480 | if (isSimilarSignature(method, name, types)) {
481 | return method;
482 | }
483 | }
484 |
485 | type = type.getSuperclass();
486 | }
487 | while (type != null);
488 |
489 | throw new NoSuchMethodException("No similar method " + name + " with params " + Arrays.toString(types) + " could be found on type " + type() + ".");
490 | }
491 |
492 | /**
493 | * Determines if a method has a "similar" signature, especially if wrapping
494 | * primitive argument types would result in an exactly matching signature.
495 | */
496 | private boolean isSimilarSignature(Method possiblyMatchingMethod, String desiredMethodName, Class>[] desiredParamTypes) {
497 | return possiblyMatchingMethod.getName().equals(desiredMethodName) && match(possiblyMatchingMethod.getParameterTypes(), desiredParamTypes);
498 | }
499 |
500 | /**
501 | * Call a constructor.
502 | *
503 | * This is a convenience method for calling
504 | * create(new Object[0])
505 | *
506 | * @return The wrapped new object, to be used for further reflection.
507 | * @throws ReflectException If any reflection exception occurred.
508 | * @see #create(Object...)
509 | */
510 | public Reflect create() throws ReflectException {
511 | return create(new Object[0]);
512 | }
513 |
514 | /**
515 | * Call a constructor.
516 | *
517 | * This is roughly equivalent to {@link Constructor#newInstance(Object...)}.
518 | * If the wrapped object is a {@link Class}, then this will create a new
519 | * object of that class. If the wrapped object is any other {@link Object},
520 | * then this will create a new object of the same type.
521 | *
522 | * Just like {@link Constructor#newInstance(Object...)}, this will try to
523 | * wrap primitive types or unwrap primitive type wrappers if applicable. If
524 | * several constructors are applicable, by that rule, the first one
525 | * encountered is called. i.e. when calling
526 | * on(C.class).create(1, 1);
527 | *
The first of the following constructors will be applied:
528 | *
529 | * public C(int param1, Integer param2);
530 | * public C(Integer param1, int param2);
531 | * public C(Number param1, Number param2);
532 | * public C(Number param1, Object param2);
533 | * public C(int param1, Object param2);
534 | *
535 | *
536 | * @param args The constructor arguments
537 | * @return The wrapped new object, to be used for further reflection.
538 | * @throws ReflectException If any reflection exception occurred.
539 | */
540 | public Reflect create(Object... args) throws ReflectException {
541 | Class>[] types = types(args);
542 |
543 | // Try invoking the "canonical" constructor, i.e. the one with exact
544 | // matching argument types
545 | try {
546 | Constructor> constructor = type().getDeclaredConstructor(types);
547 | return on(constructor, args);
548 | }
549 |
550 | // If there is no exact match, try to find one that has a "similar"
551 | // signature if primitive argument types are converted to their wrappers
552 | catch (NoSuchMethodException e) {
553 | for (Constructor> constructor : type().getDeclaredConstructors()) {
554 | if (match(constructor.getParameterTypes(), types)) {
555 | return on(constructor, args);
556 | }
557 | }
558 |
559 | throw new ReflectException(e);
560 | }
561 | }
562 |
563 | /**
564 | * Create a proxy for the wrapped object allowing to typesafely invoke
565 | * methods on it using a custom interface
566 | *
567 | * @param proxyType The interface type that is implemented by the proxy
568 | * @return A proxy for the wrapped object
569 | */
570 | @SuppressWarnings("unchecked")
571 | public
P as(final Class
proxyType) {
572 | final boolean isMap = (object instanceof Map);
573 | final InvocationHandler handler = new InvocationHandler() {
574 | @SuppressWarnings("null")
575 | @Override
576 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
577 | String name = method.getName();
578 |
579 | // Actual method name matches always come first
580 | try {
581 | return on(object).call(name, args).get();
582 | }
583 |
584 | // [#14] Emulate POJO behaviour on wrapped map objects
585 | catch (ReflectException e) {
586 | if (isMap) {
587 | Map map = (Map) object;
588 | int length = (args == null ? 0 : args.length);
589 |
590 | if (length == 0 && name.startsWith("get")) {
591 | return map.get(property(name.substring(3)));
592 | }
593 | else if (length == 0 && name.startsWith("is")) {
594 | return map.get(property(name.substring(2)));
595 | }
596 | else if (length == 1 && name.startsWith("set")) {
597 | map.put(property(name.substring(3)), args[0]);
598 | return null;
599 | }
600 | }
601 |
602 | /* [java-8] */
603 | if (method.isDefault()) {
604 | return CACHED_LOOKUP_CONSTRUCTOR
605 | .newInstance(proxyType)
606 | .unreflectSpecial(method, proxyType)
607 | .bindTo(proxy)
608 | .invokeWithArguments(args);
609 | }
610 | /* [/java-8] */
611 |
612 | throw e;
613 | }
614 | }
615 | };
616 |
617 | return (P) Proxy.newProxyInstance(proxyType.getClassLoader(), new Class[] { proxyType }, handler);
618 | }
619 |
620 | /**
621 | * Get the POJO property name of an getter/setter
622 | */
623 | private static String property(String string) {
624 | int length = string.length();
625 |
626 | if (length == 0) {
627 | return "";
628 | }
629 | else if (length == 1) {
630 | return string.toLowerCase();
631 | }
632 | else {
633 | return string.substring(0, 1).toLowerCase() + string.substring(1);
634 | }
635 | }
636 |
637 | // ---------------------------------------------------------------------
638 | // Object API
639 | // ---------------------------------------------------------------------
640 |
641 | /**
642 | * Check whether two arrays of types match, converting primitive types to
643 | * their corresponding wrappers.
644 | */
645 | private boolean match(Class>[] declaredTypes, Class>[] actualTypes) {
646 | if (declaredTypes.length == actualTypes.length) {
647 | for (int i = 0; i < actualTypes.length; i++) {
648 | if (actualTypes[i] == NULL.class)
649 | continue;
650 |
651 | if (wrapper(declaredTypes[i]).isAssignableFrom(wrapper(actualTypes[i])))
652 | continue;
653 |
654 | return false;
655 | }
656 |
657 | return true;
658 | }
659 | else {
660 | return false;
661 | }
662 | }
663 |
664 | /**
665 | * {@inheritDoc}
666 | */
667 | @Override
668 | public int hashCode() {
669 | return object.hashCode();
670 | }
671 |
672 | /**
673 | * {@inheritDoc}
674 | */
675 | @Override
676 | public boolean equals(Object obj) {
677 | if (obj instanceof Reflect) {
678 | return object.equals(((Reflect) obj).get());
679 | }
680 |
681 | return false;
682 | }
683 |
684 | /**
685 | * {@inheritDoc}
686 | */
687 | @Override
688 | public String toString() {
689 | return object.toString();
690 | }
691 |
692 | // ---------------------------------------------------------------------
693 | // Utility methods
694 | // ---------------------------------------------------------------------
695 |
696 | /**
697 | * Wrap an object created from a constructor
698 | */
699 | private static Reflect on(Constructor> constructor, Object... args) throws ReflectException {
700 | try {
701 | return on(accessible(constructor).newInstance(args));
702 | }
703 | catch (Exception e) {
704 | throw new ReflectException(e);
705 | }
706 | }
707 |
708 | /**
709 | * Wrap an object returned from a method
710 | */
711 | private static Reflect on(Method method, Object object, Object... args) throws ReflectException {
712 | try {
713 | accessible(method);
714 |
715 | if (method.getReturnType() == void.class) {
716 | method.invoke(object, args);
717 | return on(object);
718 | }
719 | else {
720 | return on(method.invoke(object, args));
721 | }
722 | }
723 | catch (Exception e) {
724 | throw new ReflectException(e);
725 | }
726 | }
727 |
728 | /**
729 | * Unwrap an object
730 | */
731 | private static Object unwrap(Object object) {
732 | if (object instanceof Reflect) {
733 | return ((Reflect) object).get();
734 | }
735 |
736 | return object;
737 | }
738 |
739 | /**
740 | * Get an array of types for an array of objects
741 | *
742 | * @see Object#getClass()
743 | */
744 | private static Class>[] types(Object... values) {
745 | if (values == null) {
746 | return new Class[0];
747 | }
748 |
749 | Class>[] result = new Class[values.length];
750 |
751 | for (int i = 0; i < values.length; i++) {
752 | Object value = values[i];
753 | result[i] = value == null ? NULL.class : value.getClass();
754 | }
755 |
756 | return result;
757 | }
758 |
759 | /**
760 | * Load a class
761 | *
762 | * @see Class#forName(String)
763 | */
764 | private static Class> forName(String name) throws ReflectException {
765 | try {
766 | return Class.forName(name);
767 | }
768 | catch (Exception e) {
769 | throw new ReflectException(e);
770 | }
771 | }
772 |
773 | private static Class> forName(String name, ClassLoader classLoader) throws ReflectException {
774 | try {
775 | return Class.forName(name, true, classLoader);
776 | }
777 | catch (Exception e) {
778 | throw new ReflectException(e);
779 | }
780 | }
781 |
782 | /**
783 | * Get the type of the wrapped object.
784 | *
785 | * @see Object#getClass()
786 | */
787 | public Class> type() {
788 | if (isClass) {
789 | return (Class>) object;
790 | }
791 | else {
792 | return object.getClass();
793 | }
794 | }
795 |
796 | /**
797 | * Get a wrapper type for a primitive type, or the argument type itself, if
798 | * it is not a primitive type.
799 | */
800 | public static Class> wrapper(Class> type) {
801 | if (type == null) {
802 | return null;
803 | }
804 | else if (type.isPrimitive()) {
805 | if (boolean.class == type) {
806 | return Boolean.class;
807 | }
808 | else if (int.class == type) {
809 | return Integer.class;
810 | }
811 | else if (long.class == type) {
812 | return Long.class;
813 | }
814 | else if (short.class == type) {
815 | return Short.class;
816 | }
817 | else if (byte.class == type) {
818 | return Byte.class;
819 | }
820 | else if (double.class == type) {
821 | return Double.class;
822 | }
823 | else if (float.class == type) {
824 | return Float.class;
825 | }
826 | else if (char.class == type) {
827 | return Character.class;
828 | }
829 | else if (void.class == type) {
830 | return Void.class;
831 | }
832 | }
833 |
834 | return type;
835 | }
836 |
837 | private static class NULL {}
838 |
839 | }
840 |
--------------------------------------------------------------------------------
/lccf-util/src/main/java/com/lccf/util/ReflectException.java:
--------------------------------------------------------------------------------
1 | package com.lccf.util;
2 |
3 | /**
4 | * A unchecked wrapper for any of Java's checked reflection exceptions:
5 | *
6 | * These exceptions are
7 | *
8 | * - {@link ClassNotFoundException}
9 | * - {@link IllegalAccessException}
10 | * - {@link IllegalArgumentException}
11 | * - {@link InstantiationException}
12 | * - {@link NoSuchMethodException}
13 | * - {@link NoSuchFieldException}
14 | * - {@link SecurityException}
15 | *
16 | *
17 | * @author Lukas Eder
18 | */
19 | public class ReflectException extends RuntimeException {
20 |
21 | /**
22 | * Generated UID
23 | */
24 | private static final long serialVersionUID = -6213149635297151442L;
25 |
26 | public ReflectException(String message) {
27 | super(message);
28 | }
29 |
30 | public ReflectException(String message, Throwable cause) {
31 | super(message, cause);
32 | }
33 |
34 | public ReflectException() {
35 | super();
36 | }
37 |
38 | public ReflectException(Throwable cause) {
39 | super(cause);
40 | }
41 | }
--------------------------------------------------------------------------------
/lccf-util/src/main/java/com/lccf/util/Reflections.java:
--------------------------------------------------------------------------------
1 | package com.lccf.util;
2 |
3 | import java.lang.reflect.Field;
4 | import java.lang.reflect.InvocationTargetException;
5 | import java.lang.reflect.Method;
6 | import java.lang.reflect.Modifier;
7 | import java.lang.reflect.ParameterizedType;
8 | import java.lang.reflect.Type;
9 |
10 | import org.apache.commons.lang3.StringUtils;
11 | import org.apache.commons.lang3.Validate;
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 |
15 | /**
16 | * 反射工具类.
17 | *
18 | * 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
19 | *
20 | */
21 | public class Reflections {
22 | private static final String SETTER_PREFIX = "set";
23 |
24 | private static final String GETTER_PREFIX = "get";
25 |
26 | private static final String CGLIB_CLASS_SEPARATOR = "$$";
27 |
28 | private static Logger logger = LoggerFactory.getLogger(Reflections.class);
29 |
30 | /**
31 | * 调用Getter方法.
32 | */
33 | public static Object invokeGetter(Object obj, String propertyName) {
34 | String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(propertyName);
35 | return invokeMethod(obj, getterMethodName, new Class[] {}, new Object[] {});
36 | }
37 |
38 | /**
39 | * 调用Setter方法, 仅匹配方法名。
40 | */
41 | public static void invokeSetter(Object obj, String propertyName, Object value) {
42 | String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(propertyName);
43 | invokeMethodByName(obj, setterMethodName, new Object[] { value });
44 | }
45 |
46 | /**
47 | * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
48 | */
49 | public static Object getFieldValue(final Object obj, final String fieldName) {
50 | Field field = getAccessibleField(obj, fieldName);
51 |
52 | if (field == null) {
53 | throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
54 | }
55 |
56 | Object result = null;
57 | try {
58 | result = field.get(obj);
59 | } catch (IllegalAccessException e) {
60 | logger.error("不可能抛出的异常{}", e.getMessage());
61 | }
62 | return result;
63 | }
64 |
65 | /**
66 | * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
67 | */
68 | public static void setFieldValue(final Object obj, final String fieldName, final Object value) {
69 | Field field = getAccessibleField(obj, fieldName);
70 |
71 | if (field == null) {
72 | throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
73 | }
74 |
75 | try {
76 | field.set(obj, value);
77 | } catch (IllegalAccessException e) {
78 | logger.error("不可能抛出的异常:{}", e.getMessage());
79 | }
80 | }
81 |
82 | /**
83 | * 直接调用对象方法, 无视private/protected修饰符.
84 | * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
85 | * 同时匹配方法名+参数类型,
86 | */
87 | public static Object invokeMethod(final Object obj, final String methodName, final Class>[] parameterTypes,
88 | final Object[] args) {
89 | Method method = getAccessibleMethod(obj, methodName, parameterTypes);
90 | if (method == null) {
91 | throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
92 | }
93 |
94 | try {
95 | return method.invoke(obj, args);
96 | } catch (Exception e) {
97 | throw convertReflectionExceptionToUnchecked(e);
98 | }
99 | }
100 |
101 | /**
102 | * 直接调用对象方法, 无视private/protected修饰符,
103 | * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
104 | * 只匹配函数名,如果有多个同名函数调用第一个。
105 | */
106 | public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
107 | Method method = getAccessibleMethodByName(obj, methodName);
108 | if (method == null) {
109 | throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
110 | }
111 |
112 | try {
113 | return method.invoke(obj, args);
114 | } catch (Exception e) {
115 | throw convertReflectionExceptionToUnchecked(e);
116 | }
117 | }
118 |
119 | /**
120 | * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
121 | *
122 | * 如向上转型到Object仍无法找到, 返回null.
123 | */
124 | public static Field getAccessibleField(final Object obj, final String fieldName) {
125 | Validate.notNull(obj, "object can't be null");
126 | Validate.notBlank(fieldName, "fieldName can't be blank");
127 | for (Class> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
128 | try {
129 | Field field = superClass.getDeclaredField(fieldName);
130 | makeAccessible(field);
131 | return field;
132 | } catch (NoSuchFieldException e) {//NOSONAR
133 | // Field不在当前类定义,继续向上转型
134 | }
135 | }
136 | return null;
137 | }
138 |
139 | /**
140 | * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
141 | * 如向上转型到Object仍无法找到, 返回null.
142 | * 匹配函数名+参数类型。
143 | *
144 | * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
145 | */
146 | public static Method getAccessibleMethod(final Object obj, final String methodName,
147 | final Class>... parameterTypes) {
148 | Validate.notNull(obj, "object can't be null");
149 | Validate.notBlank(methodName, "methodName can't be blank");
150 |
151 | for (Class> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
152 | try {
153 | Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
154 | makeAccessible(method);
155 | return method;
156 | } catch (NoSuchMethodException e) {
157 | // Method不在当前类定义,继续向上转型
158 | }
159 | }
160 | return null;
161 | }
162 |
163 | /**
164 | * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
165 | * 如向上转型到Object仍无法找到, 返回null.
166 | * 只匹配函数名。
167 | *
168 | * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
169 | */
170 | public static Method getAccessibleMethodByName(final Object obj, final String methodName) {
171 | Validate.notNull(obj, "object can't be null");
172 | Validate.notBlank(methodName, "methodName can't be blank");
173 |
174 | for (Class> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
175 | Method[] methods = searchType.getDeclaredMethods();
176 | for (Method method : methods) {
177 | if (method.getName().equals(methodName)) {
178 | makeAccessible(method);
179 | return method;
180 | }
181 | }
182 | }
183 | return null;
184 | }
185 |
186 | /**
187 | * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
188 | */
189 | public static void makeAccessible(Method method) {
190 | if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
191 | && !method.isAccessible()) {
192 | method.setAccessible(true);
193 | }
194 | }
195 |
196 | /**
197 | * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
198 | */
199 | public static void makeAccessible(Field field) {
200 | if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier
201 | .isFinal(field.getModifiers())) && !field.isAccessible()) {
202 | field.setAccessible(true);
203 | }
204 | }
205 |
206 | /**
207 | * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
208 | * 如无法找到, 返回Object.class.
209 | * eg.
210 | * public UserDao extends HibernateDao
211 | *
212 | * @param clazz The class to introspect
213 | * @return the first generic declaration, or Object.class if cannot be determined
214 | */
215 | public static Class getClassGenricType(final Class clazz) {
216 | return getClassGenricType(clazz, 0);
217 | }
218 |
219 | /**
220 | * 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
221 | * 如无法找到, 返回Object.class.
222 | *
223 | * 如public UserDao extends HibernateDao
224 | *
225 | * @param clazz clazz The class to introspect
226 | * @param index the Index of the generic ddeclaration,start from 0.
227 | * @return the index generic declaration, or Object.class if cannot be determined
228 | */
229 | public static Class getClassGenricType(final Class clazz, final int index) {
230 |
231 | Type genType = clazz.getGenericSuperclass();
232 |
233 | if (!(genType instanceof ParameterizedType)) {
234 | logger.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
235 | return Object.class;
236 | }
237 |
238 | Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
239 |
240 | if (index >= params.length || index < 0) {
241 | logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
242 | + params.length);
243 | return Object.class;
244 | }
245 | if (!(params[index] instanceof Class)) {
246 | logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
247 | return Object.class;
248 | }
249 |
250 | return (Class) params[index];
251 | }
252 |
253 | public static Class> getUserClass(Object instance) {
254 | Class clazz = instance.getClass();
255 | if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
256 | Class> superClass = clazz.getSuperclass();
257 | if (superClass != null && !Object.class.equals(superClass)) {
258 | return superClass;
259 | }
260 | }
261 | return clazz;
262 |
263 | }
264 |
265 | /**
266 | * 将反射时的checked exception转换为unchecked exception.
267 | */
268 | public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) {
269 | if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
270 | || e instanceof NoSuchMethodException) {
271 | return new IllegalArgumentException(e);
272 | } else if (e instanceof InvocationTargetException) {
273 | return new RuntimeException(((InvocationTargetException) e).getTargetException());
274 | } else if (e instanceof RuntimeException) {
275 | return (RuntimeException) e;
276 | }
277 | return new RuntimeException("Unexpected Checked Exception.", e);
278 | }
279 | }
280 |
--------------------------------------------------------------------------------
/lccf-util/src/main/java/com/lccf/util/ResponseVo.java:
--------------------------------------------------------------------------------
1 | package com.lccf.util;
2 |
3 | /**
4 | * @author lichangchao
5 | * @功能 返回json格式数据
6 | *
7 | */
8 | public class ResponseVo {
9 | private static final long serialVersionUID = -3819569459544701549L;
10 | private Integer code;
11 | private String desc;
12 | private Object data;
13 |
14 | private ResponseVo() {
15 | }
16 |
17 | public Integer getCode() {
18 | return this.code;
19 | }
20 |
21 | public ResponseVo setCode(Integer code) {
22 | this.code = code;
23 | return this;
24 | }
25 |
26 | public String getDesc() {
27 | return this.desc;
28 | }
29 |
30 | public ResponseVo setDesc(String desc) {
31 | this.desc = desc;
32 | return this;
33 | }
34 |
35 | public Object getData() {
36 | return this.data;
37 | }
38 |
39 | public ResponseVo setData(Object data) {
40 | this.data = data;
41 | return this;
42 | }
43 |
44 | public static ResponseVo BUILDER() {
45 | return new ResponseVo();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/lccf-util/src/main/java/com/lccf/util/ResponseVoUtil.java:
--------------------------------------------------------------------------------
1 | package com.lccf.util;
2 |
3 | import com.lccf.enums.EResultCode;
4 |
5 | /**
6 | * @author lichangchao
7 | * @功能 返回json格式数据
8 | *
9 | */
10 | public class ResponseVoUtil {
11 | /** 统一失败成功返回码 **/
12 | public static ResponseVo failResult(String message) {
13 | return ResponseVo.BUILDER().setCode(EResultCode.FAIL.getKey()).setDesc(message);
14 | }
15 |
16 | public static ResponseVo failResult(String Message, Object b) {
17 | return ResponseVo.BUILDER().setCode(EResultCode.FAIL.getKey()).setDesc(Message).setData(b);
18 | }
19 |
20 | public static ResponseVo successMsg(String Message) {
21 | return ResponseVo.BUILDER().setCode(EResultCode.SUCCESS.getKey()).setDesc(Message);
22 | }
23 |
24 | public static ResponseVo successData(Object data) {
25 | return ResponseVo.BUILDER().setCode(EResultCode.SUCCESS.getKey()).setData(data);
26 | }
27 |
28 | public static ResponseVo successResult(String Message, Object data) {
29 | return ResponseVo.BUILDER().setCode(EResultCode.SUCCESS.getKey()).setData(data).setDesc(Message);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lccf-util/src/main/java/com/lccf/util/SpringUtil.java:
--------------------------------------------------------------------------------
1 | package com.lccf.util;
2 |
3 | import org.springframework.beans.BeansException;
4 | import org.springframework.context.ApplicationContext;
5 | import org.springframework.context.ApplicationContextAware;
6 | import org.springframework.stereotype.Component;
7 |
8 |
9 | /**
10 | * 普通类调用Spring bean对象:
11 | *
12 | * 说明:
13 | *
14 | * 1、此类需要放到App.java同包或者子包下才能被扫描,否则失效。
15 | *
16 | * @author Administrator
17 | */
18 |
19 |
20 | public class SpringUtil implements ApplicationContextAware {
21 |
22 | private static ApplicationContext applicationContext = null;
23 |
24 |
25 | @Override
26 |
27 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
28 |
29 | if (SpringUtil.applicationContext == null) {
30 |
31 | SpringUtil.applicationContext = applicationContext;
32 |
33 | }
34 |
35 | }
36 |
37 |
38 | //获取applicationContext
39 |
40 | public static ApplicationContext getApplicationContext() {
41 |
42 | return applicationContext;
43 |
44 | }
45 |
46 |
47 | //通过name获取 Bean.
48 |
49 | public static Object getBean(String name) {
50 |
51 | return getApplicationContext().getBean(name);
52 |
53 | }
54 |
55 |
56 | //通过class获取Bean.
57 |
58 | public static T getBean(Class clazz) {
59 |
60 | return getApplicationContext().getBean(clazz);
61 |
62 | }
63 |
64 |
65 | //通过name,以及Clazz返回指定的Bean
66 |
67 | public static T getBean(String name, Class clazz) {
68 |
69 | return getApplicationContext().getBean(name, clazz);
70 |
71 | }
72 |
73 | }
--------------------------------------------------------------------------------
/lccf-util/src/main/java/com/lccf/util/StringUtil.java:
--------------------------------------------------------------------------------
1 | package com.lccf.util;
2 |
3 | import org.apache.commons.lang3.StringUtils;
4 |
5 | /**
6 | *
7 | *
8 | * @author lichangchao
9 | * @version 1.0.0
10 | * @date 2017/12/4 17:30
11 | * @see
12 | */
13 | public class StringUtil {
14 |
15 | public static String transContent(String content,String args){
16 | if(StringUtils.isEmpty(content))return "";
17 | if(StringUtils.isEmpty(args))return content;
18 | String[] arg = args.split(",");
19 | for (int i=0 ;i list, OutputStream output, String encoding) {
26 | Class clazz = Reflections.getUserClass(list.get(0));
27 | List fieldList = ExcelUtil.getMappedFiled(clazz, null);
28 | Field[] fields = new Field[fieldList.size()];
29 | for(Field f : fieldList) {
30 | ExcelVOAttribute attr = f
31 | .getAnnotation(ExcelVOAttribute.class);
32 | int col = ExcelUtil.getExcelCol(attr.column());
33 | fields[col] = f;
34 | }
35 |
36 | //写入表头
37 | ExcelVO excelVo = (ExcelVO) clazz.getAnnotation(ExcelVO.class);
38 | String[] tips = excelVo.tips();
39 | StringBuilder sb = new StringBuilder();
40 | if(tips.length > 0) {
41 | String tip = StringUtils.join(tips, ",");
42 | sb.append(tip).append("\r\n");
43 | }
44 |
45 | //append header
46 | for(Field f : fields) {
47 | ExcelVOAttribute attr = f.getAnnotation(ExcelVOAttribute.class);
48 | sb.append(attr.name()).append(",");
49 | }
50 | sb.deleteCharAt(sb.length() - 1).append("\r\n");
51 |
52 | //写入所有行
53 | for(Object o : list) {
54 | for(Field f : fields) {
55 | ExcelVOAttribute attr = f.getAnnotation(ExcelVOAttribute.class);
56 | String appendValue = "";
57 |
58 | if(attr.isExport()) {
59 | //这里只判定了Date 类型 数值类型的 未作判定
60 | Object value = Reflections.getFieldValue(o, f.getName());
61 | if(f.getType() == Date.class) {
62 | appendValue = TimeUtil.format((Date)value, attr.dateFormat());
63 | } else {
64 | appendValue = value == null ? "" : String.valueOf(value);// 如果数据存在就填入,不存在填入空格.
65 | }
66 | }
67 | sb.append(appendValue).append(",");
68 | }
69 | sb.deleteCharAt(sb.length() - 1).append("\r\n");
70 | }
71 |
72 | try {
73 | output.write(sb.toString().getBytes(encoding));
74 | output.flush();
75 | return true;
76 | } catch (IOException e) {
77 | e.printStackTrace();
78 | return false;
79 | } finally {
80 | IOUtils.closeQuietly(output);
81 | }
82 |
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/lccf-util/src/main/java/com/lccf/util/excel/ExcelUtil.java:
--------------------------------------------------------------------------------
1 | package com.lccf.util.excel;
2 |
3 | import com.lccf.util.TimeUtil;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.io.OutputStream;
7 | import java.io.PushbackInputStream;
8 | import java.lang.reflect.Field;
9 | import java.text.DecimalFormat;
10 | import java.text.SimpleDateFormat;
11 | import java.util.ArrayList;
12 | import java.util.Date;
13 | import java.util.HashMap;
14 | import java.util.List;
15 | import java.util.Map;
16 | import java.util.regex.Matcher;
17 | import java.util.regex.Pattern;
18 |
19 | import org.apache.commons.beanutils.BeanUtils;
20 | import org.apache.commons.lang3.StringUtils;
21 | import org.apache.poi.POIXMLDocument;
22 | import org.apache.poi.hssf.usermodel.HSSFCell;
23 | import org.apache.poi.hssf.usermodel.HSSFDataFormat;
24 | import org.apache.poi.hssf.usermodel.HSSFDateUtil;
25 | import org.apache.poi.hssf.usermodel.HSSFHeader;
26 | import org.apache.poi.hssf.usermodel.HSSFRow;
27 | import org.apache.poi.hssf.usermodel.HSSFSheet;
28 | import org.apache.poi.hssf.usermodel.HSSFWorkbook;
29 | import org.apache.poi.hssf.util.HSSFColor;
30 | import org.apache.poi.openxml4j.opc.OPCPackage;
31 | import org.apache.poi.poifs.filesystem.POIFSFileSystem;
32 | import org.apache.poi.ss.usermodel.Cell;
33 | import org.apache.poi.ss.usermodel.CellStyle;
34 | import org.apache.poi.ss.usermodel.Row;
35 | import org.apache.poi.ss.usermodel.Sheet;
36 | import org.apache.poi.ss.usermodel.Workbook;
37 | import org.apache.poi.util.IOUtils;
38 | import org.apache.poi.xssf.streaming.SXSSFSheet;
39 | import org.apache.poi.xssf.streaming.SXSSFWorkbook;
40 | import org.apache.poi.xssf.usermodel.XSSFWorkbook;
41 |
42 |
43 |
44 | /*
45 | * ExcelUtil工具类实现功能: 导出时传入list,即可实现导出为一个excel,其中每个对象T为Excel中的一条记录.
46 | * 导入时读取excel,得到的结果是一个list.T是自己定义的对象.
47 | * 需要导出的实体对象只需简单配置注解就能实现灵活导出,通过注解您可以方便实现下面功能: 1.实体属性配置了注解就能导出到excel中,每个属性都对应一列.
48 | * 2.列名称可以通过注解配置. 3.导出到哪一列可以通过注解配置. 4.鼠标移动到该列时提示信息可以通过注解配置.
49 | * 5.用注解设置只能下拉选择不能随意填写功能. 6.用注解设置是否只导出标题而不导出内容,这在导出内容作为模板以供用户填写时比较实用.
50 | * 本工具类以后可能还会加功能,请关注我的博客: http://blog.csdn.net/lk_blog
51 | *
52 | * TODO: 增加JSR303 验证数据准确性 返回Map>
53 | */
54 | public class ExcelUtil {
55 | Class clazz;
56 |
57 | public ExcelUtil(Class clazz) {
58 | this.clazz = clazz;
59 | }
60 |
61 | public static Workbook create(InputStream in) throws IOException, org.apache.poi.openxml4j.exceptions.InvalidFormatException {
62 | if (!in.markSupported()) {
63 | in = new PushbackInputStream(in, 8);
64 | }
65 | if (POIFSFileSystem.hasPOIFSHeader(in)) {
66 | return new HSSFWorkbook(in);
67 | }
68 | if (POIXMLDocument.hasOOXMLHeader(in)) {
69 | return new XSSFWorkbook(OPCPackage.open(in));
70 | }
71 | throw new IllegalArgumentException("你的excel版本目前poi解析不了");
72 | }
73 |
74 | /**
75 | * 导入excel we don't command big data import using excel
76 | * TODO:类型设定改用common-utils
77 | *
78 | * @throws IOException
79 | */
80 | public Map importExcel(String sheetName, InputStream input) throws Exception {
81 | int maxCol = 0;
82 | Map importMap = new HashMap<>();
83 | List successList = new ArrayList();
84 | List failList = new ArrayList();
85 | Workbook workbook = null;
86 | try {
87 | workbook = create(input);
88 | Sheet sheet = workbook.getSheet(sheetName);
89 | if (!sheetName.trim().equals("")) {
90 | sheet = workbook.getSheet(sheetName);// 如果指定sheet名,则取指定sheet中的内容.
91 | }
92 | if (sheet == null) {
93 | sheet = workbook.getSheetAt(0); // 如果传入的sheet名不存在则默认指向第1个sheet.
94 | }
95 | int rows = sheet.getPhysicalNumberOfRows();
96 | ExcelVO anno = clazz.getAnnotation(ExcelVO.class);
97 | int minRows = anno == null ? 0 : anno.skipLine();
98 | if (rows > minRows) {// 有数据时才处理
99 | // Field[] allFields = clazz.getDeclaredFields();// 得到类的所有field.
100 | List allFields = getMappedFiled(clazz, null);
101 |
102 | Map fieldsMap = new HashMap();// 定义一个map用于存放列的序号和field.
103 | for (Field field : allFields) {
104 | // 将有注解的field存放到map中.
105 | if (field.isAnnotationPresent(ExcelVOAttribute.class)) {
106 | ExcelVOAttribute attr = field.getAnnotation(ExcelVOAttribute.class);
107 | int col = getExcelCol(attr.column());// 获得列号
108 | maxCol = Math.max(col, maxCol);
109 | // System.out.println(col + "====" + field.getName());
110 | field.setAccessible(true);// 设置类的私有字段属性可访问.
111 | fieldsMap.put(col, field);
112 | }
113 | }
114 | for (int i = minRows; i < rows; i++) {
115 | Row row = sheet.getRow(i);
116 | // int cellNum = row.getPhysicalNumberOfCells();
117 | // int cellNum = row.getLastCellNum();
118 | int cellNum = maxCol;
119 | T entity = null;
120 | for (int j = 0; j <= cellNum; j++) {
121 | Cell cell = row.getCell(j);
122 |
123 | if (cell == null) {
124 | continue;
125 | }
126 | Field field = fieldsMap.get(j);// 从map中得到对应列的field.
127 | if (field == null) {
128 | continue;
129 | }
130 | ExcelVOAttribute voAttrAnn = field.getAnnotation(ExcelVOAttribute.class);
131 | String c = parseExcel(cell, voAttrAnn.decimalLength());
132 |
133 | if (c == null || c.equals("")) {
134 | continue;
135 | }
136 | entity = (entity == null ? clazz.newInstance() : entity);// 如果不存在实例则新建.
137 |
138 | // 取得类型,并根据对象类型设置值.
139 | Class> fieldType = field.getType();
140 | if (String.class == fieldType) {
141 | field.set(entity, String.valueOf(c));
142 | } else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) {
143 | field.set(entity, Integer.parseInt(c));
144 | } else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) {
145 | field.set(entity, Long.valueOf(c));
146 | } else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) {
147 | field.set(entity, Float.valueOf(c));
148 | } else if ((Short.TYPE == fieldType) || (Short.class == fieldType)) {
149 | field.set(entity, Short.valueOf(c));
150 | } else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) {
151 | field.set(entity, Double.valueOf(c));
152 | } else if (Character.TYPE == fieldType) {
153 | if ((c != null) && (c.length() > 0)) {
154 | field.set(entity, Character.valueOf(c.charAt(0)));
155 | }
156 | } else if (Date.class == fieldType) {
157 | if ((c != null) && (c.length() > 0)) {
158 | field.set(entity, TimeUtil.parse(c));
159 | }
160 | }
161 |
162 | ResJson resJson = validField(field, c);
163 | // 如果验证不成功则设置错误信息
164 | if (!resJson.isSuccess()) {
165 | BeanUtils.copyProperty(entity, "errorMessage", resJson.getMessage());
166 | }
167 | }
168 |
169 | if (entity != null) {
170 | String errorMessage = BeanUtils.getProperty(entity, "errorMessage");
171 |
172 | if (StringUtils.isEmpty(errorMessage)) {
173 | successList.add(entity);
174 |
175 | } else {
176 | failList.add(entity);
177 | }
178 | }
179 | }
180 | }
181 | importMap.put(true, successList);
182 | importMap.put(false, failList);
183 | } finally {
184 | IOUtils.closeQuietly(workbook);
185 | }
186 |
187 | return importMap;
188 | }
189 |
190 | /**
191 | * 处理cell中特殊的数据类型 特别是日期类型
192 | *
193 | * @param cell
194 | * @return
195 | */
196 | private String parseExcel(Cell cell, int decimalLength) {
197 | String result = new String();
198 | switch (cell.getCellType()) {
199 | case HSSFCell.CELL_TYPE_NUMERIC:// 数字类型
200 | if (HSSFDateUtil.isCellDateFormatted(cell)) {// 处理日期格式、时间格式
201 | SimpleDateFormat sdf = null;
202 | if (cell.getCellStyle().getDataFormat() == HSSFDataFormat.getBuiltinFormat("h:mm")) {
203 | sdf = new SimpleDateFormat("HH:mm");
204 | } else {// 日期
205 | sdf = new SimpleDateFormat("yyyy-MM-dd");
206 | }
207 | Date date = cell.getDateCellValue();
208 | result = sdf.format(date);
209 | } else if (cell.getCellStyle().getDataFormat() == 58) {
210 | // 处理自定义日期格式:m月d日(通过判断单元格的格式id解决,id的值是58)
211 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
212 | double value = cell.getNumericCellValue();
213 | Date date = org.apache.poi.ss.usermodel.DateUtil.getJavaDate(value);
214 | result = sdf.format(date);
215 | } else {
216 | double value = cell.getNumericCellValue();
217 | CellStyle style = cell.getCellStyle();
218 | DecimalFormat format = new DecimalFormat();
219 | String temp = style.getDataFormatString();
220 | // 单元格设置成常规
221 | if (temp.equals("General") || temp.contains("@")) {
222 | String pattern = decidePattern(decimalLength);
223 | format.applyPattern(pattern);
224 | }
225 | result = format.format(value);
226 | }
227 | break;
228 | case HSSFCell.CELL_TYPE_STRING:// String类型
229 | result = cell.getRichStringCellValue().toString();
230 | break;
231 | case HSSFCell.CELL_TYPE_BLANK:
232 | result = "";
233 | default:
234 | result = "";
235 | break;
236 | }
237 | return result == null?null:result.trim();
238 | }
239 |
240 | private String decidePattern(int decimalLength) {
241 | StringBuilder sb = new StringBuilder(decimalLength > 0 ? "#." : "#");
242 | int length = decimalLength;
243 | while (length-- > 0) {
244 | sb.append("#");
245 | }
246 |
247 | return sb.toString();
248 | }
249 |
250 | /**
251 | * 对list数据源将其里面的数据导入到excel表单
252 | *
253 | * @param sheetName 工作表的名称
254 | * @param output java输出流
255 | */
256 | public boolean exportExcel(List lists[], String sheetNames[], OutputStream output) {
257 | if (lists.length != sheetNames.length) {
258 | System.out.println("数组长度不一致");
259 | return false;
260 | }
261 |
262 | SXSSFWorkbook workbook = new SXSSFWorkbook(500);// 产生工作薄对象
263 |
264 | for (int ii = 0; ii < lists.length; ii++) {
265 | List list = lists[ii];
266 | String sheetName = sheetNames[ii];
267 |
268 | List fields = getMappedFiled(clazz, null);
269 |
270 | SXSSFSheet sheet = workbook.createSheet();// 产生工作表对象
271 |
272 | workbook.setSheetName(ii, sheetName);
273 |
274 | Row row;
275 | Cell cell;// 产生单元格
276 | CellStyle style = workbook.createCellStyle();
277 | style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
278 | style.setFillBackgroundColor(HSSFColor.GREY_40_PERCENT.index);
279 |
280 | // 判定表头是否需要需要增加额外的提示
281 | int startNo = 0;
282 |
283 | ExcelVO excelVo = clazz.getAnnotation(ExcelVO.class);
284 | String[] tips = excelVo.tips();
285 | if (tips.length > 0) {
286 | row = sheet.createRow(startNo++);
287 | for (int i = 0; i < tips.length; i++) {
288 | cell = row.createCell(i);// 创建列
289 | cell.setCellType(HSSFCell.CELL_TYPE_STRING);
290 | cell.setCellValue(tips[i]);// 写入列名
291 | }
292 | }
293 |
294 | row = sheet.createRow(startNo++);// 产生一行
295 | // 写入各个字段的列头名称
296 | for (int i = 0; i < fields.size(); i++) {
297 | Field field = fields.get(i);
298 | ExcelVOAttribute attr = field.getAnnotation(ExcelVOAttribute.class);
299 | int col = getExcelCol(attr.column());// 获得列号
300 | cell = row.createCell(col);// 创建列
301 | cell.setCellType(HSSFCell.CELL_TYPE_STRING);// 设置列中写入内容为String类型
302 | cell.setCellValue(attr.name());// 写入列名
303 |
304 | // 如果设置了提示信息则鼠标放上去提示.
305 | // if (!attr.prompt().trim().equals("")) {
306 | // setHSSFPrompt(sheet, "", attr.prompt(), 1, 100, col, col);//
307 | // 这里默认设了2-101列提示.
308 | // }
309 | // // 如果设置了combo属性则本列只能选择不能输入
310 | // if (attr.combo().length > 0) {
311 | // setHSSFValidation(sheet, attr.combo(), 1, 100, col, col);//
312 | // 这里默认设了2-101列只能选择不能输入.
313 | // }
314 | cell.setCellStyle(style);
315 | }
316 |
317 | int endNo = list.size();
318 | // 写入各条记录,每条记录对应excel表中的一行
319 | for (int i = 0; i < endNo; i++) {
320 | row = sheet.createRow(i + startNo);
321 | T vo = list.get(i); // 得到导出对象.
322 | for (int j = 0; j < fields.size(); j++) {
323 | Field field = fields.get(j);// 获得field.
324 | field.setAccessible(true);// 设置实体类私有属性可访问
325 | ExcelVOAttribute attr = field.getAnnotation(ExcelVOAttribute.class);
326 | try {
327 | // 根据ExcelVOAttribute中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
328 | if (attr.isExport()) {
329 | cell = row.createCell(getExcelCol(attr.column()));// 创建cell
330 | cell.setCellType(HSSFCell.CELL_TYPE_STRING);
331 | Object o = field.get(vo);
332 | if (o == null) {
333 | cell.setCellValue("");
334 | } else {
335 | if (field.getType() == Date.class) {
336 | cell.setCellValue(TimeUtil.format((Date) o, attr.dateFormat()));
337 | } else {
338 | cell.setCellValue(String.valueOf(o));// 如果数据存在就填入,不存在填入空格.
339 | }
340 | }
341 | }
342 | } catch (IllegalArgumentException e) {
343 | e.printStackTrace();
344 | } catch (IllegalAccessException e) {
345 | e.printStackTrace();
346 | }
347 | }
348 | }
349 | }
350 |
351 | try {
352 | output.flush();
353 | workbook.write(output);
354 | return true;
355 | } catch (IOException e) {
356 | e.printStackTrace();
357 | System.out.println("Output is closed ");
358 | return false;
359 | } finally {
360 | IOUtils.closeQuietly(workbook);
361 | IOUtils.closeQuietly(output);
362 | }
363 |
364 | }
365 |
366 | /**
367 | * 对list数据源将其里面的数据导入到excel表单
368 | *
369 | * @param sheetName 工作表的名称
370 | * @param sheetSize 每个sheet中数据的行数,此数值必须小于65536
371 | * @param output java输出流
372 | */
373 | public boolean exportExcel(List list, String sheetName, OutputStream output) {
374 | List[] lists = new ArrayList[1];
375 | lists[0] = list;
376 |
377 | String[] sheetNames = new String[1];
378 | sheetNames[0] = sheetName;
379 |
380 | return exportExcel(lists, sheetNames, output);
381 | }
382 |
383 | /**
384 | * 将EXCEL中A,B,C,D,E列映射成0,1,2,3
385 | *
386 | * @param col
387 | */
388 | public static int getExcelCol(String col) {
389 | col = col.toUpperCase();
390 | // 从-1开始计算,字母重1开始运算。这种总数下来算数正好相同。
391 | int count = -1;
392 | char[] cs = col.toCharArray();
393 | for (int i = 0; i < cs.length; i++) {
394 | count += (cs[i] - 64) * Math.pow(26, cs.length - 1 - i);
395 | }
396 | return count;
397 | }
398 | /**
399 | * 设置单元格上提示
400 | *
401 | * @param sheet 要设置的sheet.
402 | * @param promptTitle 标题
403 | * @param promptContent 内容
404 | * @param firstRow 开始行
405 | * @param endRow 结束行
406 | * @param firstCol 开始列
407 | * @param endCol 结束列
408 | * @return 设置好的sheet.
409 | */
410 | // public static Sheet setHSSFPrompt(SXSSFSheet sheet, String promptTitle,
411 | // String promptContent, int firstRow, int endRow, int firstCol,
412 | // int endCol) {
413 | // // 构造constraint对象
414 | // DVConstraint constraint = DVConstraint
415 | // .createCustomFormulaConstraint("DD1");
416 | // // 四个参数分别是:起始行、终止行、起始列、终止列
417 | // CellRangeAddressList regions = new CellRangeAddressList(firstRow,
418 | // endRow, firstCol, endCol);
419 | // // 数据有效性对象
420 | // HSSFDataValidation data_validation_list = new HSSFDataValidation(
421 | // regions, constraint);
422 | // sheet.addValidationData(data_validation_list);
423 | //
424 | // return sheet;
425 | // }
426 |
427 | /**
428 | * 设置某些列的值只能输入预制的数据,显示下拉框.
429 | *
430 | * @param sheet 要设置的sheet.
431 | * @param textlist 下拉框显示的内容
432 | * @param firstRow 开始行
433 | * @param endRow 结束行
434 | * @param firstCol 开始列
435 | * @param endCol 结束列
436 | * @return 设置好的sheet.
437 | */
438 | // public static Sheet setHSSFValidation(Sheet sheet,
439 | // String[] textlist, int firstRow, int endRow, int firstCol,
440 | // int endCol) {
441 | // // 加载下拉列表内容
442 | // DVConstraint constraint = DVConstraint
443 | // .createExplicitListConstraint(textlist);
444 | // // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
445 | // CellRangeAddressList regions = new CellRangeAddressList(firstRow,
446 | // endRow, firstCol, endCol);
447 | // // 数据有效性对象
448 | // HSSFDataValidation data_validation_list = new HSSFDataValidation(
449 | // regions, constraint);
450 | // sheet.addValidationData(data_validation_list);
451 | // return sheet;
452 | // }
453 |
454 | /**
455 | * 得到实体类所有通过注解映射了数据表的字段
456 | *
457 | * @param map
458 | * @return
459 | */
460 | public static List getMappedFiled(Class clazz, List fields) {
461 | if (fields == null) {
462 | fields = new ArrayList();
463 | }
464 |
465 | Field[] allFields = clazz.getDeclaredFields();// 得到所有定义字段
466 | // 得到所有field并存放到一个list中.
467 | for (Field field : allFields) {
468 | if (field.isAnnotationPresent(ExcelVOAttribute.class)) {
469 | fields.add(field);
470 | }
471 | }
472 | if (clazz.getSuperclass() != null && !clazz.getSuperclass().equals(Object.class)) {
473 | getMappedFiled(clazz.getSuperclass(), fields);
474 | }
475 |
476 | return fields;
477 | }
478 |
479 | // 表头生成
480 | public static void createTableHeader(HSSFSheet sheet, String[] tableHeader, String sheetname) {
481 | HSSFRow row = null;
482 | HSSFHeader header = sheet.getHeader();
483 | header.setCenter(sheetname);
484 | row = sheet.createRow(0);
485 | for (int i = 0; i < tableHeader.length; i++) {
486 | setCell(row, i, tableHeader[i]);
487 | }
488 | }
489 |
490 | // 写入单元格
491 | @SuppressWarnings("deprecation")
492 | public static void setCell(HSSFRow row, int index, String value) {
493 | HSSFCell cell = row.createCell((short) index);
494 | cell.setCellType(HSSFCell.CELL_TYPE_STRING);
495 | cell.setCellValue(value);
496 | }
497 | /**
498 | *
499 | * 解析excel表格头信息
500 | * @throws IOException
501 | */
502 | public String[] paseExcelHead(String sheetName, InputStream input) throws Exception {
503 | Workbook workbook = create(input);
504 | Sheet sheet = workbook.getSheet(sheetName);
505 | if (!sheetName.trim().equals("")) {
506 | sheet = workbook.getSheet(sheetName);// 如果指定sheet名,则取指定sheet中的内容.
507 | }
508 | if (sheet == null) {
509 | sheet = workbook.getSheetAt(0); // 如果传入的sheet名不存在则默认指向第1个sheet.
510 | }
511 | Row row = sheet.getRow(0);
512 | int cells = row.getPhysicalNumberOfCells();
513 | String[] excelHead = new String[cells];
514 | for (int j = 0; j < cells; j++) {
515 | Cell cell = row.getCell(j);
516 | String c = parseExcel(cell, 0);
517 | excelHead[j] = c;
518 | }
519 | return excelHead;
520 | }
521 |
522 |
523 | public boolean viladHead(String sheetName, InputStream input,String[] defineHeads){
524 | boolean b = true;
525 | try {
526 | String[] heads = this.paseExcelHead(sheetName,input);
527 | if(defineHeads.length>heads.length){
528 | return false;
529 | }
530 | for(int i = 0;i= min && length <= max)) {
558 | b = false;
559 | }
560 | // 验证是否必填
561 | if (required && StringUtils.isEmpty(value)) {
562 | b = false;
563 | }
564 | if (!StringUtils.isEmpty(value)) {
565 | // 验证是否符合正则规则
566 | Pattern r = Pattern.compile(regx);
567 | Matcher m = r.matcher(value);
568 | if (!m.find()) {
569 | b = false;
570 | }
571 | }
572 | if (!b) {
573 | filed = message;
574 | }
575 | }
576 | return new ResJson(b, filed);
577 | }
578 |
579 | public static class ResJson {
580 | boolean isSuccess;
581 | String message;
582 |
583 | public ResJson(boolean isSuccess, String message) {
584 | this.message = message;
585 | this.isSuccess = isSuccess;
586 | }
587 |
588 | public boolean isSuccess() {
589 | return isSuccess;
590 | }
591 |
592 | public void setSuccess(boolean success) {
593 | isSuccess = success;
594 | }
595 |
596 | public String getMessage() {
597 | return message;
598 | }
599 |
600 | public void setMessage(String message) {
601 | this.message = message;
602 | }
603 | }
604 |
605 | }
606 |
--------------------------------------------------------------------------------
/lccf-util/src/main/java/com/lccf/util/excel/ExcelVO.java:
--------------------------------------------------------------------------------
1 | package com.lccf.util.excel;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 | import java.lang.annotation.Target;
6 |
7 | @Retention(RetentionPolicy.RUNTIME)
8 | @Target( { java.lang.annotation.ElementType.TYPE })
9 | public @interface ExcelVO {
10 |
11 | int skipLine() default 1; // 默认跳过表头
12 | String[] tips() default {}; //导出excel时 添加表头顶部的说明
13 | }
14 |
--------------------------------------------------------------------------------
/lccf-util/src/main/java/com/lccf/util/excel/ExcelVOAttribute.java:
--------------------------------------------------------------------------------
1 | package com.lccf.util.excel;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 | import java.lang.annotation.Target;
6 |
7 | @Retention(RetentionPolicy.RUNTIME)
8 | @Target( { java.lang.annotation.ElementType.FIELD })
9 | public @interface ExcelVOAttribute {
10 |
11 | /**
12 | * 导出到Excel中的名字.
13 | */
14 | String name();
15 |
16 | /**
17 | * 配置列的名称,对应A,B,C,D....
18 | */
19 | String column();
20 |
21 | /**
22 | * 提示信息
23 | */
24 | String prompt() default "";
25 |
26 | /**
27 | * 设置只能选择不能输入的列内容.
28 | */
29 | String[] combo() default {};
30 |
31 | /**
32 | * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
33 | */
34 | boolean isExport() default true;
35 |
36 | /**
37 | * 日期导出格式
38 | */
39 | String dateFormat() default "yyyy-MM-dd HH:mm:ss";
40 |
41 | /**
42 | * 数值转String时所保留小树点数
43 | */
44 | int decimalLength() default 0;
45 | }
46 |
--------------------------------------------------------------------------------
/lccf-util/src/main/java/com/lccf/util/excel/ExcelValidAttribute.java:
--------------------------------------------------------------------------------
1 | package com.lccf.util.excel;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 | import java.lang.annotation.Target;
6 |
7 | @Retention(RetentionPolicy.RUNTIME)
8 | @Target( { java.lang.annotation.ElementType.FIELD })
9 | public @interface ExcelValidAttribute {
10 | boolean required() default false;
11 | String regexp() default "";
12 | String message() default "";
13 | int min() default 0;
14 | int max() default Integer.MAX_VALUE;
15 | }
16 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.lccf
7 | lccf
8 | 0.0.1-SNAPSHOT
9 | pom
10 |
11 |
12 |
13 | lcc-web
14 | lccf-util
15 |
16 | lccf-base
17 |
18 |
19 | lccf
20 | lccf 基于springboot 搭建的框架
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter-parent
25 | 1.5.1.RELEASE
26 |
27 |
28 |
29 |
30 | UTF-8
31 | UTF-8
32 | 1.8
33 | 1
34 |
35 |
36 |
37 |
38 | org.springframework.boot
39 | spring-boot-starter
40 |
41 |
42 |
43 | org.springframework.boot
44 | spring-boot-starter-logging
45 |
46 |
47 |
48 |
49 |
50 | org.springframework.boot
51 | spring-boot-starter-aop
52 |
53 |
54 |
55 | org.springframework.boot
56 | spring-boot-starter-data-jpa
57 |
58 |
59 | org.springframework.boot
60 | spring-boot-starter-data-redis
61 |
62 |
63 | org.springframework.boot
64 | spring-boot-starter-cache
65 |
66 |
67 | org.springframework.boot
68 | spring-boot-starter-validation
69 |
70 |
71 | org.springframework.boot
72 | spring-boot-starter-web
73 |
74 |
75 |
76 |
77 | org.springframework.boot
78 | spring-boot-starter-test
79 | test
80 |
81 |
82 |
83 | org.springframework.boot
84 | spring-boot-devtools
85 | true
86 |
87 |
88 | org.springframework.boot
89 | spring-boot-configuration-processor
90 | true
91 |
92 |
93 | org.springframework.boot
94 | spring-boot-starter-security
95 |
96 |
97 | org.springframework.boot
98 | spring-boot-starter-thymeleaf
99 |
100 |
101 | org.springframework.boot
102 | spring-boot-starter-mail
103 |
104 |
105 | org.springframework
106 | springloaded
107 |
108 |
109 | io.jsonwebtoken
110 | jjwt
111 | 0.7.0
112 |
113 |
114 | mysql
115 | mysql-connector-java
116 |
117 |
118 | io.springfox
119 | springfox-swagger2
120 | 2.4.0
121 |
122 |
123 | io.springfox
124 | springfox-swagger-ui
125 | 2.4.0
126 |
127 |
128 | io.springfox
129 | springfox-staticdocs
130 | 2.4.0
131 |
132 |
133 |
134 | org.springframework.restdocs
135 | spring-restdocs-mockmvc
136 | 1.1.2.RELEASE
137 |
138 |
139 | net.sf.dozer
140 | dozer
141 | 5.4.0
142 |
143 |
144 | org.slf4j
145 | slf4j-log4j12
146 |
147 |
148 |
149 |
150 | commons-beanutils
151 | commons-beanutils
152 | 1.9.3
153 |
154 |
155 | org.apache.commons
156 | commons-lang3
157 | 3.6
158 |
159 |
160 |
161 |
162 |
163 | com.baidu.disconf
164 | disconf-client
165 | 2.6.36
166 |
167 |
168 | javax.inject
169 | javax.inject
170 | ${javax.inject.version}
171 |
172 |
173 |
174 | com.fasterxml.jackson.datatype
175 | jackson-datatype-hibernate4
176 | ${jackson.version}
177 |
178 |
179 | com.fasterxml.jackson.datatype
180 | jackson-datatype-hppc
181 | ${jackson.version}
182 |
183 |
184 | com.fasterxml.jackson.datatype
185 | jackson-datatype-json-org
186 | ${jackson.version}
187 |
188 |
189 | com.fasterxml.jackson.datatype
190 | jackson-datatype-jsr310
191 |
192 |
193 | com.fasterxml.jackson.core
194 | jackson-annotations
195 | ${jackson.version}
196 |
197 |
198 | com.fasterxml.jackson.core
199 | jackson-databind
200 | ${jackson.version}
201 |
202 |
203 | com.fasterxml.jackson.core
204 | jackson-core
205 | ${jackson.version}
206 |
207 |
208 |
209 | com.relops
210 | snowflake
211 | 1.1
212 |
213 |
214 |
215 |
216 | org.springframework.boot
217 | spring-boot-starter-log4j2
218 |
219 |
220 |
221 |
222 | com.fasterxml.jackson.dataformat
223 | jackson-dataformat-yaml
224 |
225 |
226 |
227 |
228 |
229 | org.projectlombok
230 | lombok
231 | 1.16.8
232 |
233 |
234 |
235 |
236 |
237 | com.graphql-java
238 | graphql-java
239 | 3.0.0
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 | org.apache.maven.plugins
251 | maven-compiler-plugin
252 |
253 | ${java.version}
254 | ${java.version}
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
--------------------------------------------------------------------------------