Jump to content
Sign in to follow this  
Jacek Laskowski

[Spring4D] Factory and "Unsatisfied constructor"

Recommended Posts

I have problem with one factory.

 


definition

  TSQLDataSuiteWorkerMethod = procedure(const aDataSuite : ISQLDataSuite) of object;

  TSQLDataSuite = class(TInterfacedObject, ISQLDataSuite)
  [...]
  public
    constructor Create(const aTableName: RawByteString;
                       const aSQLKind: TModifyingSQLKind;
                       const aProcessSQL : Boolean = True;
                       const aBeforeWorkerMethod: TSQLDataSuiteWorkerMethod = nil;
                       const aAfterWorkerMethod: TSQLDataSuiteWorkerMethod = nil); reintroduce;
  end;
  
  {$M+}
  TSQLDataSuiteFactory = reference to function(const aTableName: RawByteString;
                                               const aSQLKind: TModifyingSQLKind;
                                               const aProcessSQL : Boolean = True;
                                               const aBeforeWorkerMethod: TSQLDataSuiteWorkerMethod = nil;
                                               const aAfterWorkerMethod: TSQLDataSuiteWorkerMethod = nil): ISQLDataSuite;
  {$M-}                                             

 
container registration  

 

  aContainer.RegisterType<TSQLDataSuite>.Implements<ISQLDataSuite>;
  aContainer.RegisterFactory<TSQLDataSuiteFactory>;

 
 
resolve in code:

fSQLDataSuiteFactory : TSQLDataSuiteFactory;

var
  Data: ISQLDataSuite;
begin
  Data := fSQLDataSuiteFactory('TableName', TModifyingSQLKind.SQLInsert, True, nil, nil);

 

And after last l get exception from Spring4D:

 

Unsatisfied constructor on TSQLDataSuite

 

What have I forgotten?

 

I use in the program dozens of factories, classes and interfaces, all based on the spring container, everything works correctly, only this case I cannot understand.


ps. maybe it's worth opening a subforum for Spring4D?

 

 

Share this post


Link to post

When looking for the correct constructor to match the algo tries to match the parameters given with the parameters required by the constructor.

However it does not allow injecting nil which is the reason it does not consider this constructor.

 

As for a subforum - there is already a forum for Spring4D at https://groups.google.com/forum/#!forum/spring4d

Share this post


Link to post

I add new constructor to TSQLDataSuite:

 

    constructor Create(const aTableName: RawByteString; const aSQLKind: TModifyingSQLKind; const aProcessSQL : Boolean); overload;

 

And new factory:

 

  ISQLDataSuiteFactory = interface(IInvokable) ['{A101FA06-ED33-478A-9066-821BC8C5E2AE}']
  
    function Create(const aTableName: RawByteString;
                    const aSQLKind: TModifyingSQLKind;
                    const aProcessSQL : Boolean ): ISQLDataSuite; overload;
  
    function Create(const aTableName: RawByteString;
                    const aSQLKind: TModifyingSQLKind;
                    const aProcessSQL : Boolean;
                    const aBeforeWorkerMethod: TSQLDataSuiteWorkerMethod;
                    const aAfterWorkerMethod: TSQLDataSuiteWorkerMethod): ISQLDataSuite; overload;
  end;

 

but after call:
 

var
 fSQLDataSuiteFactory : ISQLDataSuiteFactory;

[...]

  lData := fSQLDataSuiteFactory.Create('TableName', TModifyingSQLKind.SQLInsert, True);

I stiil get exception:

Unsatisfied constructor on type: TSQLDataSuite

 

How to do it right?

Share this post


Link to post

When I comment on one of the constructors, then the factory was working properly.

 

TSQLDataSuite = class(TInterfacedObject, ISQLDataSuite) 
[...] 
public
//  constructor Create(const aTableName: RawByteString; 
//                     const aSQLKind: TModifyingSQLKind; 
//                     const aProcessSQL : Boolean = True; 
//                     const aBeforeWorkerMethod: TSQLDataSuiteWorkerMethod = nil; 
//                     const aAfterWorkerMethod: TSQLDataSuiteWorkerMethod = nil); overload;

  constructor Create(const aTableName: RawByteString; 
                     const aSQLKind: TModifyingSQLKind; 
                     const aProcessSQL : Boolean); overload;
end;

 

There is a problem with factory when a class has two active constructors. But I can't understand it.

Share this post


Link to post

Then you are doing something wrong - can't repro

 

{$APPTYPE CONSOLE}

uses
  Spring.Container;

type
  TModifyingSQLKind = (SQLInsert);
  TSQLDataSuiteWorkerMethod = procedure of object;

 ISQLDataSuite = interface
   ['{068D3552-CBA6-4AAE-9061-59FA6407FF8C}']
 end;

 TSQLDataSuite = class(TInterfacedObject, ISQLDataSuite)
  public
    constructor Create(const aTableName: RawByteString;
                       const aSQLKind: TModifyingSQLKind;
                       const aProcessSQL : Boolean); overload;
    constructor Create(const aTableName: RawByteString;
                       const aSQLKind: TModifyingSQLKind;
                       const aProcessSQL : Boolean = True;
                       const aBeforeWorkerMethod: TSQLDataSuiteWorkerMethod = nil;
                       const aAfterWorkerMethod: TSQLDataSuiteWorkerMethod = nil); overload;
  end;

  ISQLDataSuiteFactory = interface(IInvokable)
    ['{A101FA06-ED33-478A-9066-821BC8C5E2AE}']
    function Create(const aTableName: RawByteString;
                    const aSQLKind: TModifyingSQLKind;
                    const aProcessSQL : Boolean ): ISQLDataSuite; overload;
    function Create(const aTableName: RawByteString;
                    const aSQLKind: TModifyingSQLKind;
                    const aProcessSQL : Boolean;
                    const aBeforeWorkerMethod: TSQLDataSuiteWorkerMethod;
                    const aAfterWorkerMethod: TSQLDataSuiteWorkerMethod): ISQLDataSuite; overload;
  end;

{ TSQLDataSuite }

constructor TSQLDataSuite.Create(const aTableName: RawByteString;
  const aSQLKind: TModifyingSQLKind; const aProcessSQL: Boolean);
begin
  Writeln('create');
end;

constructor TSQLDataSuite.Create(const aTableName: RawByteString;
  const aSQLKind: TModifyingSQLKind; const aProcessSQL: Boolean;
  const aBeforeWorkerMethod, aAfterWorkerMethod: TSQLDataSuiteWorkerMethod);
begin
end;

var
  fSQLDataSuiteFactory: ISQLDataSuiteFactory;
begin
  globalContainer.RegisterType<TSQLDataSuite>.Implements<ISQLDataSuite>;
  globalContainer.RegisterFactory<ISQLDataSuiteFactory>();
  globalContainer.Build;
  fSQLDataSuiteFactory := globalContainer.Resolve<ISQLDataSuiteFactory>();

  fSQLDataSuiteFactory.Create('TableName', TModifyingSQLKind.SQLInsert, True);
  Readln;
end.

 

Share this post


Link to post

@Stefan Glienke

Your example works, my code doesn't. It's identical*.
I spent a lot of hours and energy modifying the code from left to right... I finally found it!

Please add a line in your example before registering classes in the container:

 

  globalContainer.AddExtension<TActivatorContainerExtension>;

 

and then check it out...  🙂

 

I'm very tired of it... give me a tip how to fix it, please.

 

* - almost

Share this post


Link to post

I think you mean this piece of code (from the SelectEligibleConstructor method):

 

    end).TakeWhile(
    function(const injection: IInjection): Boolean
    begin
      if maxCount = -1 then
        maxCount := injection.DependencyCount;
      if targetType = nil then
        targetType := injection.Target.Parent;
      Result := (injection.DependencyCount = maxCount)
        and (targetType = injection.Target.Parent);
    end).Where(...

But how (at this point) to get to the list of arguments and their types to choose the right constructor?

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×