001/* 002 * ============================================================================ 003 * Copyright © 2002-2023 by Thomas Thrien. 004 * All Rights Reserved. 005 * ============================================================================ 006 * Licensed to the public under the agreements of the GNU Lesser General Public 007 * License, version 3.0 (the "License"). You may obtain a copy of the License at 008 * 009 * http://www.gnu.org/licenses/lgpl.html 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 014 * License for the specific language governing permissions and limitations 015 * under the License. 016 */ 017 018package org.tquadrat.foundation.config.ap.impl.codebuilders; 019 020import static javax.lang.model.element.Modifier.FINAL; 021import static javax.lang.model.element.Modifier.PRIVATE; 022import static javax.lang.model.element.Modifier.PUBLIC; 023import static javax.lang.model.element.Modifier.STATIC; 024import static org.apiguardian.api.API.Status.MAINTAINED; 025import static org.tquadrat.foundation.config.SpecialPropertyType.CONFIG_PROPERTY_RESOURCEBUNDLE; 026import static org.tquadrat.foundation.config.ap.PropertySpec.PropertyFlag.ENVIRONMENT_VARIABLE; 027import static org.tquadrat.foundation.config.ap.PropertySpec.PropertyFlag.EXEMPT_FROM_TOSTRING; 028import static org.tquadrat.foundation.config.ap.PropertySpec.PropertyFlag.GETTER_IS_DEFAULT; 029import static org.tquadrat.foundation.config.ap.PropertySpec.PropertyFlag.PROPERTY_IS_SPECIAL; 030import static org.tquadrat.foundation.config.ap.PropertySpec.PropertyFlag.SYSTEM_PREFERENCE; 031import static org.tquadrat.foundation.config.ap.PropertySpec.PropertyFlag.SYSTEM_PROPERTY; 032import static org.tquadrat.foundation.config.ap.impl.CodeBuilder.StandardField.STD_FIELD_ListenerSupport; 033import static org.tquadrat.foundation.config.ap.impl.CodeBuilder.StandardField.STD_FIELD_ReadLock; 034import static org.tquadrat.foundation.config.ap.impl.CodeBuilder.StandardField.STD_FIELD_WriteLock; 035import static org.tquadrat.foundation.config.ap.impl.CodeBuilder.StandardMethod.STD_METHOD_AddListener; 036import static org.tquadrat.foundation.config.ap.impl.CodeBuilder.StandardMethod.STD_METHOD_GetRessourceBundle; 037import static org.tquadrat.foundation.config.ap.impl.CodeBuilder.StandardMethod.STD_METHOD_RemoveListener; 038import static org.tquadrat.foundation.config.ap.impl.CodeBuilder.StandardMethod.STD_METHOD_ToString; 039import static org.tquadrat.foundation.javacomposer.Primitives.VOID; 040import static org.tquadrat.foundation.javacomposer.SuppressableWarnings.INSTANCE_VARIABLE_OF_CONCRETE_CLASS; 041import static org.tquadrat.foundation.javacomposer.SuppressableWarnings.THROW_CAUGHT_LOCALLY; 042import static org.tquadrat.foundation.javacomposer.SuppressableWarnings.UNCHECKED; 043import static org.tquadrat.foundation.javacomposer.SuppressableWarnings.createSuppressWarningsAnnotation; 044import static org.tquadrat.foundation.lang.CommonConstants.EMPTY_STRING; 045import static org.tquadrat.foundation.lang.Objects.nonNull; 046import static org.tquadrat.foundation.util.StringUtils.repeat; 047 048import java.io.FileNotFoundException; 049import java.io.IOException; 050import java.util.Properties; 051import java.util.StringJoiner; 052import java.util.concurrent.locks.ReentrantReadWriteLock; 053 054import org.apiguardian.api.API; 055import org.tquadrat.foundation.annotation.ClassVersion; 056import org.tquadrat.foundation.config.ConfigurationChangeListener; 057import org.tquadrat.foundation.config.ap.PropertySpec; 058import org.tquadrat.foundation.config.spi.ConfigChangeListenerSupport; 059import org.tquadrat.foundation.exception.ValidationException; 060import org.tquadrat.foundation.javacomposer.MethodSpec; 061import org.tquadrat.foundation.javacomposer.ParameterizedTypeName; 062import org.tquadrat.foundation.javacomposer.TypeName; 063import org.tquadrat.foundation.lang.AutoLock; 064import org.tquadrat.foundation.lang.CommonConstants; 065import org.tquadrat.foundation.lang.Objects; 066 067/** 068 * The 069 * {@linkplain org.tquadrat.foundation.config.ap.impl.CodeBuilder code builder implementation} 070 * for the basic stuff, as defined in 071 * {@link org.tquadrat.foundation.config.ConfigBeanSpec}. 072 * 073 * @extauthor Thomas Thrien - thomas.thrien@tquadrat.org 074 * @version $Id: ConfigBeanBuilder.java 1076 2023-10-03 18:36:07Z tquadrat $ 075 * @UMLGraph.link 076 * @since 0.1.0 077 */ 078@SuppressWarnings( "OverlyCoupledClass" ) 079@ClassVersion( sourceVersion = "$Id: ConfigBeanBuilder.java 1076 2023-10-03 18:36:07Z tquadrat $" ) 080@API( status = MAINTAINED, since = "0.1.0" ) 081public final class ConfigBeanBuilder extends CodeBuilderBase 082{ 083 /*--------------*\ 084 ====** Constructors **===================================================== 085 \*--------------*/ 086 /** 087 * Creates a new instance of {@code ConfigBeanBuilder}. 088 * 089 * @param context The code generator context. 090 */ 091 public ConfigBeanBuilder( final CodeGeneratorContext context ) 092 { 093 super( context ); 094 } // ConfigBeanBuilder() 095 096 /*---------*\ 097 ====** Methods **========================================================== 098 \*---------*/ 099 /** 100 * Adds the listener support to the new class. 101 */ 102 private final void addListenerSupport() 103 { 104 //---* Add the listener support *------------------------------------- 105 final var field = getComposer().fieldBuilder( ConfigChangeListenerSupport.class, STD_FIELD_ListenerSupport.toString() , PRIVATE, FINAL ) 106 .addAnnotation( createSuppressWarningsAnnotation( getComposer(), INSTANCE_VARIABLE_OF_CONCRETE_CLASS ) ) 107 .addJavadoc( 108 """ 109 The support for the configuration change listener. 110 """ ) 111 .build(); 112 addField( STD_FIELD_ListenerSupport, field ); 113 114 //---* Initialise the listener support *------------------------------- 115 var code = getComposer().codeBlockBuilder() 116 .add( 117 """ 118 //---* Initialise the listener support *------------------------------- 119 """ ) 120 .addStatement( "$N = new $T( this )", getField( STD_FIELD_ListenerSupport ), ConfigChangeListenerSupport.class ) 121 .build(); 122 addConstructorCode( code ); 123 124 //---* Add the listener management methods *--------------------------- 125 final var param1 = getComposer().parameterBuilder( ConfigurationChangeListener.class, "listener", FINAL ) 126 .build(); 127 code = getComposer().codeBlockBuilder() 128 .addStatement( "$N.addListener( $N )", getField( STD_FIELD_ListenerSupport ), param1 ) 129 .build(); 130 var method = getComposer().methodBuilder( STD_METHOD_AddListener.toString() ) 131 .addModifiers( PUBLIC, FINAL ) 132 .addAnnotation( Override.class ) 133 .addJavadoc( getComposer().createInheritDocComment() ) 134 .addParameter( param1 ) 135 .returns( VOID ) 136 .addCode( code ) 137 .build(); 138 addMethod( STD_METHOD_AddListener, method ); 139 140 code = getComposer().codeBlockBuilder() 141 .addStatement( "$N.removeListener( $N )", getField( STD_FIELD_ListenerSupport ), param1 ) 142 .build(); 143 method = getComposer().methodBuilder( STD_METHOD_RemoveListener.toString() ) 144 .addModifiers( PUBLIC, FINAL ) 145 .addAnnotation( Override.class ) 146 .addJavadoc( getComposer().createInheritDocComment() ) 147 .addParameter( param1 ) 148 .returns( VOID ) 149 .addCode( code ) 150 .build(); 151 addMethod( STD_METHOD_RemoveListener, method ); 152 } // addListenerSupport() 153 154 /** 155 * Adds locking support to the new class. 156 */ 157 private final void addLockSupport() 158 { 159 //---* Add the locks *------------------------------------------------- 160 var field = getComposer().fieldBuilder( AutoLock.class, STD_FIELD_ReadLock.toString(), PRIVATE, FINAL ) 161 .addJavadoc( 162 """ 163 The "read" lock. 164 """ ) 165 .build(); 166 addField( STD_FIELD_ReadLock, field ); 167 168 field = getComposer().fieldBuilder( AutoLock.class, STD_FIELD_WriteLock.toString(), PRIVATE, FINAL ) 169 .addJavadoc( 170 """ 171 The "write" lock. 172 """ ) 173 .build(); 174 addField( STD_FIELD_WriteLock, field ); 175 176 //---* Initialise the locks *------------------------------------------ 177 final var code = getComposer().codeBlockBuilder() 178 .add( 179 """ 180 181 //---* Create the locks and initialise them *-------------------------- 182 """ ) 183 .addStatement( "final var lock = new $T()", ReentrantReadWriteLock.class ) 184 .addStatement( "$N = $T.of( lock.readLock() )", getField( STD_FIELD_ReadLock ), AutoLock.class ) 185 .addStatement( "$N = $T.of( lock.writeLock() )", getField( STD_FIELD_WriteLock ), AutoLock.class ) 186 .build(); 187 addConstructorCode( code ); 188 } // addLockSupport() 189 190 /** 191 * Adds "unchecked" to the 192 * {@link SuppressWarnings} 193 * annotation for the constructor if the given type is a 194 * {@link java.util.List}, 195 * {@link java.util.Set}, 196 * {@link java.util.Map} 197 * or an otherwise parameterised type. 198 * 199 * @param typeName The type to check. 200 * 201 * @see ParameterizedTypeName 202 */ 203 private final void addUnchecked( final TypeName typeName ) 204 { 205 if( typeName instanceof ParameterizedTypeName ) addConstructorSuppressedWarning( UNCHECKED ); 206 } // addUnchecked() 207 208 /** 209 * {@inheritDoc} 210 */ 211 @Override 212 public final void build() 213 { 214 //---* Generate the default stuff *------------------------------------ 215 addListenerSupport(); 216 if( isSynchronized() ) addLockSupport(); 217 218 //---* Generate the properties *--------------------------------------- 219 for( final var iterator = getProperties(); iterator.hasNext(); ) 220 { 221 generateProperty( iterator.next() ); 222 } 223 224 //---* Create the initialisation code in the constructor *------------- 225 getConfiguration().getInitDataMethod() 226 .ifPresent( this::composeInitializationCodeFromMethod ); 227 getConfiguration().getInitDataResource() 228 .ifPresent( this::composeInitializationCodeFromResource ); 229 230 //---* Create 'toString()' *------------------------------------------- 231 createToString(); 232 } // build() 233 234 /** 235 * Composes the constructor code that initialises the properties from the 236 * result of a call to the {@code initData()} method. 237 * 238 * @param method The {@code initData()} method. 239 */ 240 private final void composeInitializationCodeFromMethod( final MethodSpec method ) 241 { 242 final var builder = getComposer().codeBlockBuilder() 243 .add( 244 """ 245 246 /* 247 * Initialise the properties from '$1N()'. 248 */ 249 """, method 250 ) 251 .beginControlFlow( 252 """ 253 try 254 """ 255 ); 256 257 if( method.hasModifier( STATIC ) ) 258 { 259 builder.addStatement( "final var initData = $1T.initData()", getConfiguration().getSpecification() ); 260 } 261 else 262 { 263 builder.addStatement( "final var initData = initData()" ); 264 } 265 266 builder.beginControlFlow( 267 """ 268 if( isNull( initData ) ) 269 """ ) 270 .addStaticImport( Objects.class, "isNull" ) 271 .addStatement( 272 """ 273 throw new $T( "initData() returns null" )""", ValidationException.class ) 274 .endControlFlow(); 275 276 PropertyLoop: 277 for( final var iterator = getProperties(); iterator.hasNext(); ) 278 { 279 final var propertySpec = iterator.next().merge(); 280 if( propertySpec.hasFlag( GETTER_IS_DEFAULT ) ) continue PropertyLoop; 281 if( propertySpec.hasFlag( PROPERTY_IS_SPECIAL ) 282 && propertySpec.getSpecialPropertyType().filter( spt -> spt == CONFIG_PROPERTY_RESOURCEBUNDLE ).isEmpty() ) 283 { 284 continue PropertyLoop; 285 } 286 if( propertySpec.hasFlag( SYSTEM_PROPERTY ) ) continue PropertyLoop; 287 if( propertySpec.hasFlag( ENVIRONMENT_VARIABLE ) ) continue PropertyLoop; 288 if( propertySpec.hasFlag( SYSTEM_PREFERENCE ) ) continue PropertyLoop; 289 290 final var propertyType = propertySpec.getPropertyType(); 291 final var field = propertySpec.getFieldName(); 292 final var propertyName = propertySpec.getPropertyName(); 293 addUnchecked( propertyType ); 294 295 builder.beginControlFlow( 296 """ 297 if( initData.containsKey( $1S ) ) 298 """, propertyName ) 299 .addStatement( "$1N = ($2T) initData.get( $3S )", field, propertyType.box(), propertyName ) 300 .endControlFlow(); 301 } // PropertyLoop: 302 303 builder.nextControlFlow( 304 """ 305 306 catch( final $1T t ) 307 """, Throwable.class ) 308 .addStatement( 309 """ 310 final var eiie = new $1T( "initData() failed" )""", ExceptionInInitializerError.class ) 311 .addStatement( "eiie.addSuppressed( t )" ) 312 .addStatement( "throw eiie" ) 313 .endControlFlow(); 314 315 //---* Add the code to the constructor *------------------------------- 316 addConstructorCode( builder.build() ); 317 } // composeInitializationCodeFromMethod() 318 319 /** 320 * Composes the constructor code that initialises the properties from the 321 * provided resource. 322 * 323 * @param resourceName The name of the resource. 324 */ 325 @SuppressWarnings( "OverlyComplexMethod" ) 326 private final void composeInitializationCodeFromResource( final String resourceName ) 327 { 328 //---* The code that loads the properties from the resource *---------- 329 final var builder = getComposer().codeBlockBuilder() 330 .add( 331 """ 332 333 /* 334 * Load initialisation data from resource "$1L". 335 */ 336 """, resourceName ) 337 .beginControlFlow( EMPTY_STRING ) 338 .addStatement( "final var resource = $1T.class.getResource( $2S )", getConfiguration().getSpecification(), resourceName ) 339 .beginControlFlow( 340 """ 341 if( isNull( resource ) ) 342 """ ) 343 .addStaticImport( Objects.class, "isNull" ) 344 .addStatement( 345 """ 346 final var fnfe = new $1T( "Resource '$2L'" )""", FileNotFoundException.class, resourceName ) 347 .addStatement( """ 348 final var eiie = new $1T( "Cannot find resource '$2L'" )""", ExceptionInInitializerError.class, resourceName ) 349 .addStatement( "eiie.addSuppressed( fnfe )" ) 350 .addStatement( "throw eiie" ) 351 .endControlFlow() 352 .add( "\n" ) 353 .addStatement( "final var initData = new $1T()", Properties.class ) 354 .beginControlFlow( 355 """ 356 try( final var inputStream = resource.openStream() ) 357 """ ) 358 .addStatement( "initData.load( inputStream )" ) 359 .nextControlFlow( 360 """ 361 362 catch( final $1T e ) 363 """, IOException.class ) 364 .addStatement( 365 """ 366 final var eiie = new $1T( "Cannot load resource '%s'".formatted( resource.toExternalForm() ) )""", ExceptionInInitializerError.class ) 367 .addStatement( "eiie.addSuppressed( e )" ) 368 .addStatement( "throw eiie" ) 369 .endControlFlow() 370 .add( 371 """ 372 373 /* 374 * Initialise the properties. 375 */ 376 """ ) 377 .addStatement( "$1T value", String.class ); 378 379 PropertyLoop: 380 for( final var iterator = getProperties(); iterator.hasNext(); ) 381 { 382 final var propertySpec = iterator.next().merge(); 383 if( propertySpec.hasFlag( GETTER_IS_DEFAULT ) ) continue PropertyLoop; 384 if( propertySpec.hasFlag( PROPERTY_IS_SPECIAL ) ) continue PropertyLoop; 385 if( propertySpec.hasFlag( SYSTEM_PROPERTY ) ) continue PropertyLoop; 386 if( propertySpec.hasFlag( ENVIRONMENT_VARIABLE ) ) continue PropertyLoop; 387 if( propertySpec.hasFlag( SYSTEM_PREFERENCE ) ) continue PropertyLoop; 388 389 /* 390 * Without a StringConverter we cannot initialise the property from 391 * the resource. 392 */ 393 if( propertySpec.getStringConverterClass().isEmpty() ) continue PropertyLoop; 394 final var stringConverter = propertySpec.getStringConverterClass().get(); 395 396 final var field = propertySpec.getFieldName(); 397 final var propertyName = propertySpec.getPropertyName(); 398 399 builder.add( "\n" ) 400 .addStatement( "value = initData.getProperty( $1S )", propertyName ) 401 .beginControlFlow( 402 """ 403 if( nonNull( value ) ) 404 """ ) 405 .addStaticImport( Objects.class, "nonNull" ); 406 switch( determineStringConverterInstantiation( stringConverter, propertySpec.isEnum() ) ) 407 { 408 case BY_INSTANCE -> builder.addStatement( "final var stringConverter = $1T.INSTANCE", stringConverter ); 409 case THROUGH_CONSTRUCTOR -> builder.addStatement( "final var stringConverter = new $1T()", stringConverter ); 410 case AS_ENUM -> builder.addStatement( "final var stringConverter = new $1T( $2T.class )", stringConverter, propertySpec.getPropertyType() ); 411 } 412 builder.addStatement( "$N = stringConverter.fromString( value )", field ) 413 .endControlFlow(); 414 } // PropertyLoop: 415 builder.endControlFlow(); 416 417 addConstructorSuppressedWarning( THROW_CAUGHT_LOCALLY ); 418 419 //---* Add the code block *-------------------------------------------- 420 addConstructorCode( builder.build() ); 421 } // composeInitializationCodeFromResource() 422 423 /** 424 * <p>{@summary Creates the implementation of the method 425 * {@link Object#toString()} 426 * for the configuration bean.} The output of that method will be like 427 * this:</p> 428 * <pre><code><<i>ClassName</i>> <b>[</b><<i>PropertyName</i>> <b>= "</b><<i>PropertyValue</i>><b>"</b>[<b>,</b> …]<b>]</b></code></pre> 429 */ 430 @SuppressWarnings( "OverlyComplexMethod" ) 431 private final void createToString() 432 { 433 //---* Create the 'toString()' method *-------------------------------- 434 final var builder = getComposer().createToStringBuilder() 435 .addStatement( "final var prefix = format ( $1S, getClass().getName() )", "%s [" ) 436 .addStaticImport( String.class, "format" ) 437 .addStatement( "final var joiner = new $1T( $2S, prefix, $3S )", StringJoiner.class, ", ", "]" ) 438 .addCode( "\n" ); 439 440 //---* Add the locking *----------------------------------------------- 441 final var lock = getConfiguration().getSynchronizationRequired() 442 ? getField( STD_FIELD_ReadLock ) 443 : null; 444 if( nonNull( lock) ) builder.beginControlFlow( 445 """ 446 try( final var ignored = $N.lock() ) 447 """, lock ); 448 final var commentLen = nonNull( lock ) ? 67 : 71; 449 450 //---* Add the code *-------------------------------------------------- 451 var addEmptyLine = false; 452 PropertyLoop: 453 for( final var iterator = getProperties(); iterator.hasNext(); ) 454 { 455 final var propertySpec = iterator.next().merge(); 456 if( propertySpec.hasFlag( EXEMPT_FROM_TOSTRING ) ) continue PropertyLoop; 457 458 if( addEmptyLine ) builder.addCode( "\n" ); 459 addEmptyLine = true; 460 final var propertyName = propertySpec.getPropertyName(); 461 final var comment = "//---* Property \"%1$s\" *%2$s".formatted( propertyName, repeat( '-', 80 ) ) 462 .substring( 0, commentLen ); 463 builder.addCode( 464 """ 465 $L 466 """, comment ) 467 .beginControlFlow( EMPTY_STRING ); 468 469 if( !propertySpec.hasFlag( GETTER_IS_DEFAULT ) ) 470 { 471 //---* We have a field … *------------------------------------- 472 final var field = propertySpec.getFieldName(); 473 474 if( propertySpec.getStringConverterClass().isPresent() ) 475 { 476 final var stringConverter = propertySpec.getStringConverterClass().get(); 477 switch( determineStringConverterInstantiation( stringConverter, propertySpec.isEnum() ) ) 478 { 479 case BY_INSTANCE -> builder.addStatement( "final var stringConverter = $1T.INSTANCE", stringConverter ); 480 case THROUGH_CONSTRUCTOR -> builder.addStatement( "final var stringConverter = new $1T()", stringConverter ); 481 case AS_ENUM -> builder.addStatement( "final var stringConverter = new $1T( $2T.class )", stringConverter, propertySpec.getPropertyType() ); 482 } 483 builder.addStatement( "final var value = stringConverter.toString( $1L )", field ) 484 .addStatement( 485 """ 486 joiner.add( format( "$1N = \\"%1$$s\\"", nonNull( value ) ? value : NULL_STRING ) )\ 487 """, propertyName ) 488 .addStaticImport( Objects.class, "nonNull" ) 489 .addStaticImport( CommonConstants.class, "NULL_STRING" ) 490 .addStaticImport( String.class, "format" ); 491 } 492 else 493 { 494 builder.addStatement( 495 """ 496 joiner.add( format( "$1N = \\"%1$$S\\"", $2T.toString( $3L ) ) )\ 497 """, propertyName, Objects.class, field ) 498 .addStaticImport( String.class, "format" ); 499 } 500 } 501 else if( propertySpec.getGetterMethodName().isPresent()) 502 { 503 //---* We just have a getter … *------------------------------- 504 final var getterMethod = propertySpec.getGetterMethodName().get(); 505 if( propertySpec.getStringConverterClass().isPresent() ) 506 { 507 final var stringConverter = propertySpec.getStringConverterClass().get(); 508 switch( determineStringConverterInstantiation( stringConverter, propertySpec.isEnum() ) ) 509 { 510 case BY_INSTANCE -> builder.addStatement( "final var stringConverter = $1T.INSTANCE", stringConverter ); 511 case THROUGH_CONSTRUCTOR -> builder.addStatement( "final var stringConverter = new $1T()", stringConverter ); 512 case AS_ENUM -> builder.addStatement( "final var stringConverter = new $1T( $2T.class )", stringConverter, propertySpec.getPropertyType() ); 513 } 514 builder.addStatement( "final var value = stringConverter.toString( $1L() )", getterMethod ) 515 .addStatement( 516 """ 517 joiner.add( format( "$1N = \\"%1$$s\\"", nonNull( value ) ? value : NULL_STRING ) )\ 518 """, propertyName ) 519 .addStaticImport( Objects.class, "nonNull" ) 520 .addStaticImport( CommonConstants.class, "NULL_STRING" ) 521 .addStaticImport( String.class, "format" ); 522 } 523 else 524 { 525 builder.addStatement( 526 """ 527 joiner.add( format( "$1N = \\"%1$$s\\"", $2T.toString( $3L() ) ) )\ 528 """, propertyName, Objects.class, getterMethod ) 529 .addStaticImport( String.class, "format" ); 530 } 531 } 532 builder.endControlFlow(); 533 } // PropertiesLoop: 534 535 //---* Cleanup *------------------------------------------------------- 536 if( nonNull( lock) ) builder.endControlFlow(); 537 538 builder.addCode( 539 """ 540 541 //---* Create the return value *--------------------------------------- 542 """ 543 ) 544 .addStatement( "final var retValue = joiner.toString()" ) 545 .addCode( getComposer().createReturnStatement() ); 546 547 addMethod( STD_METHOD_ToString, builder.build() ); 548 } // createToString() 549 550 /** 551 * Generates the methods, fields and other code for the given property. 552 * 553 * @param rawProperty The property specification. 554 */ 555 private final void generateProperty( final PropertySpec rawProperty ) 556 { 557 final var property = rawProperty.merge(); 558 559 //---* Create the field *---------------------------------------------- 560 property.createField( this ).ifPresent( this::addField ); 561 562 /* 563 * Create the constructor code for the initialisation of the property. 564 */ 565 property.createConstructorFragment( this ).ifPresent( this::addConstructorCode ); 566 567 //---* Create the getter *--------------------------------------------- 568 if( property.getPropertyName().equals( CONFIG_PROPERTY_RESOURCEBUNDLE.getPropertyName() ) ) 569 { 570 property.createGetter( this ).ifPresent( p -> addMethod( STD_METHOD_GetRessourceBundle, p ) ); 571 } 572 else 573 { 574 property.createGetter( this ).ifPresent( this::addMethod ); 575 } 576 577 //---* Create the getter *--------------------------------------------- 578 property.createSetter( this ).ifPresent( this::addMethod ); 579 580 //---* Create the 'add' method *--------------------------------------- 581 property.createAddMethod( this ).ifPresent( this::addMethod ); 582 } // generateProperty() 583} 584// class ConfigBeanBuilder 585 586/* 587 * End of File 588 */