|
15 | 15 | */
|
16 | 16 | package org.springframework.batch.item.file.builder;
|
17 | 17 |
|
| 18 | +import java.lang.reflect.ParameterizedType; |
| 19 | +import java.lang.reflect.Type; |
| 20 | +import java.lang.reflect.TypeVariable; |
18 | 21 | import java.util.ArrayList;
|
19 | 22 | import java.util.Arrays;
|
20 | 23 | import java.util.List;
|
|
31 | 34 | import org.springframework.batch.item.file.transform.FieldExtractor;
|
32 | 35 | import org.springframework.batch.item.file.transform.FormatterLineAggregator;
|
33 | 36 | import org.springframework.batch.item.file.transform.LineAggregator;
|
| 37 | +import org.springframework.batch.item.file.transform.RecordFieldExtractor; |
| 38 | +import org.springframework.cglib.core.TypeUtils; |
| 39 | +import org.springframework.core.GenericTypeResolver; |
| 40 | +import org.springframework.core.ParameterizedTypeReference; |
| 41 | +import org.springframework.core.ResolvableType; |
34 | 42 | import org.springframework.core.io.WritableResource;
|
35 | 43 | import org.springframework.util.Assert;
|
| 44 | +import org.springframework.util.ClassUtils; |
| 45 | +import org.springframework.util.ObjectUtils; |
| 46 | +import org.springframework.util.ReflectionUtils; |
36 | 47 |
|
37 | 48 | /**
|
38 | 49 | * A builder implementation for the {@link FlatFileItemWriter}
|
|
46 | 57 | */
|
47 | 58 | public class FlatFileItemWriterBuilder<T> {
|
48 | 59 |
|
49 |
| - protected Log logger = LogFactory.getLog(getClass()); |
| 60 | + protected static Log logger = LogFactory.getLog(FlatFileItemWriterBuilder.class); |
50 | 61 |
|
51 | 62 | private WritableResource resource;
|
52 | 63 |
|
@@ -372,21 +383,41 @@ public FormatterLineAggregator<T> build() {
|
372 | 383 | formatterLineAggregator.setMaximumLength(this.maximumLength);
|
373 | 384 |
|
374 | 385 | if (this.fieldExtractor == null) {
|
375 |
| - BeanWrapperFieldExtractor<T> beanWrapperFieldExtractor = new BeanWrapperFieldExtractor<>(); |
376 |
| - beanWrapperFieldExtractor.setNames(this.names.toArray(new String[this.names.size()])); |
| 386 | + FieldExtractor<T> fieldExtractor = null; |
| 387 | + logger.info("No field extractor specified, trying to introspect item type from generic type information"); |
| 388 | + Class<T> itemType = null; |
377 | 389 | try {
|
378 |
| - beanWrapperFieldExtractor.afterPropertiesSet(); |
379 |
| - } |
380 |
| - catch (Exception e) { |
| 390 | + itemType = getItemType(); |
| 391 | + if (itemType != null && itemType.isRecord()) { |
| 392 | + fieldExtractor = new RecordFieldExtractor<>(itemType); |
| 393 | + } |
| 394 | + else { |
| 395 | + BeanWrapperFieldExtractor<T> beanWrapperFieldExtractor = new BeanWrapperFieldExtractor<>(); |
| 396 | + beanWrapperFieldExtractor.setNames(this.names.toArray(new String[this.names.size()])); |
| 397 | + beanWrapperFieldExtractor.afterPropertiesSet(); |
| 398 | + fieldExtractor = beanWrapperFieldExtractor; |
| 399 | + } |
| 400 | + } catch (Exception e) { |
381 | 401 | throw new IllegalStateException("Unable to initialize FormatterLineAggregator", e);
|
382 | 402 | }
|
383 |
| - this.fieldExtractor = beanWrapperFieldExtractor; |
| 403 | + this.fieldExtractor = fieldExtractor; |
384 | 404 | }
|
385 | 405 |
|
386 | 406 | formatterLineAggregator.setFieldExtractor(this.fieldExtractor);
|
387 | 407 | return formatterLineAggregator;
|
388 | 408 | }
|
389 | 409 |
|
| 410 | + private Class<T> getItemType() throws ClassNotFoundException { |
| 411 | + TypeVariable<? extends Class<? extends FormattedBuilder>>[] typeParameters = this.getClass() |
| 412 | + .getTypeParameters(); |
| 413 | + if (typeParameters != null && typeParameters.length > 0) { |
| 414 | + TypeVariable<? extends Class<? extends FormattedBuilder>> typeParameter = typeParameters[0]; |
| 415 | + String typeName = typeParameter.getName(); |
| 416 | + return (Class<T>) ClassUtils.forName(typeName, this.getClass().getClassLoader()); |
| 417 | + } |
| 418 | + return null; |
| 419 | + } |
| 420 | + |
390 | 421 | }
|
391 | 422 |
|
392 | 423 | /**
|
@@ -453,21 +484,41 @@ public DelimitedLineAggregator<T> build() {
|
453 | 484 | }
|
454 | 485 |
|
455 | 486 | if (this.fieldExtractor == null) {
|
456 |
| - BeanWrapperFieldExtractor<T> beanWrapperFieldExtractor = new BeanWrapperFieldExtractor<>(); |
457 |
| - beanWrapperFieldExtractor.setNames(this.names.toArray(new String[this.names.size()])); |
| 487 | + FieldExtractor<T> fieldExtractor = null; |
| 488 | + logger.info("No field extractor specified, trying to introspect item type from generic type information"); |
| 489 | + Class<T> itemType = null; |
458 | 490 | try {
|
459 |
| - beanWrapperFieldExtractor.afterPropertiesSet(); |
460 |
| - } |
461 |
| - catch (Exception e) { |
| 491 | + itemType = getItemType(); |
| 492 | + if (itemType != null && itemType.isRecord()) { |
| 493 | + fieldExtractor = new RecordFieldExtractor<>(itemType); |
| 494 | + } |
| 495 | + else { |
| 496 | + BeanWrapperFieldExtractor<T> beanWrapperFieldExtractor = new BeanWrapperFieldExtractor<>(); |
| 497 | + beanWrapperFieldExtractor.setNames(this.names.toArray(new String[this.names.size()])); |
| 498 | + beanWrapperFieldExtractor.afterPropertiesSet(); |
| 499 | + fieldExtractor = beanWrapperFieldExtractor; |
| 500 | + } |
| 501 | + } catch (Exception e) { |
462 | 502 | throw new IllegalStateException("Unable to initialize DelimitedLineAggregator", e);
|
463 | 503 | }
|
464 |
| - this.fieldExtractor = beanWrapperFieldExtractor; |
| 504 | + this.fieldExtractor = fieldExtractor; |
465 | 505 | }
|
466 | 506 |
|
467 | 507 | delimitedLineAggregator.setFieldExtractor(this.fieldExtractor);
|
468 | 508 | return delimitedLineAggregator;
|
469 | 509 | }
|
470 | 510 |
|
| 511 | + private Class<T> getItemType() throws ClassNotFoundException { |
| 512 | + TypeVariable<? extends Class<? extends DelimitedBuilder>>[] typeParameters = this.getClass() |
| 513 | + .getTypeParameters(); |
| 514 | + if (typeParameters != null && typeParameters.length > 0) { |
| 515 | + TypeVariable<? extends Class<? extends DelimitedBuilder>> typeParameter = typeParameters[0]; |
| 516 | + String typeName = typeParameter.getName(); |
| 517 | + return (Class<T>) ClassUtils.forName(typeName, this.getClass().getClassLoader()); |
| 518 | + } |
| 519 | + return null; |
| 520 | + } |
| 521 | + |
471 | 522 | }
|
472 | 523 |
|
473 | 524 | /**
|
|
0 commit comments