Expanders 5.32.0
In this release of Expanders, we've cleaned up some long-deprecated code that still uses UserContext
as the main
context transport object. There's also been several improvements in the infrastructure to improve ease of use for
functional keys.
Resources
The expansion resources below provide Expanders 5.32.0
.
Resource | Version |
---|---|
Expanders | 5.32.0 |
nsx-default-stack | 2023.15.2 |
rest-jaxrs-stack | 3.27.0 |
Changes and improvements
Functional key infrastructure
FinderResolver
A new class FinderResolver
has been introduced, which is called from the Bean.find()
method in the logic layer. This
class will automatically resolve the DataRefs for any field operator pairs that target link fields. Resolving means that
it will resolve the DataRef against the database in case there's no database identifier present in it. While much of the
methods in the stack already did this, the finders still did not, which often caused some confusion. The finder would
not work as intended if the database identifier was not present in the DataRefs. This resolution will only occur if
there is no database identifier in the DataRef, so the impact on performance should be negligible in existing code.
Agent.getDetails()
The Agent.getDetails(DataRef)
method did not behave quite the same as LocalAgent.getDetails(DataRef)
. Even though
the same code was called down the line, the way it worked on the remote agent would lose all information in the DataRef
except for the database identifier. This meant that it had to be resolved prior to use. This issue has now been resolved
as well, by having it call getProjection()
instead, just like its LocalAgent
counterpart.
Context transport
In a distant past, there was no Context
class, rather the only context was UserContext
ans it was used to pass all
context information. This has been replaced for years in favor of the Context
class and the UserContext
has since
only been used for actual information about the user. Therefore, we've started removing a lot of this deprecated
infrastructure that still relied on UserContext
where Context
should be used instead. Some of these methods include
Agent.getAgent(UserContext)
and LocalAgent.getLocalAgent()
.
Deprecating old methods
We intend to remove a lot of clutter that has been created in the stack over the years, with methods for backwards
compatibility that should no longer be used. We've started marking many of these methods as deprecated for removal, so
it is already clear to developers that these should not be used in new code and should be refactored if they are still
in use in older code. A prime example of these are methods in the stack that still use a database identifier as a Long
parameter, rather than a DataRef. We'll be marking more of these as deprecated in future releases.
Typed finders
The typed finders system is now the default for all applications. The option finders.enableTypedFinders
is now no
longer required. Typed finders means that generics are used through the stack for finders, to ensure that the compiler
will verify that they are not used with infrastructure of the wrong DataElement. It also changes the FinderBean to use
mapped method references for the finder implementations, rather than reflection. This means that it is no longer
possible to defined custom finders that are not present in the model.
Migration guide
Migrating Agent.getDetails()
With Agent.getDetails()
now behaving the same as LocalAgent.getDetails()
, resolving the DataRef ahead of calling
this is no longer required. This code can be cleaned up by removing the resolution step, certainly in the control layer
where it will be less efficient to resolve from in most cases.
Migrating context transport
Migrating for the context transport changes should be trivial. All methods that were previously available with
UserContext
which were changed, now only take Context
. For pretty much all of these, the Context
alternative has
been present for years. Code calling these should now simply use Context
instead of UserContext
. Some common
examples include:
- Passing
parameterContext.getContext()
insteadparameterContext.getUserContext()
. - Using
Context.from(userContext)
in placed where onlyUserContext
is available.
Any places where now only a Context
object is available, but the UserContext
itself is needed, it should be
retrieved from the Context
itself using Context.find(UserContext.class)
. This call will return an Optional<>
, so
the result can easily be handled in many ways. an empty UserContext
was often used if no UserContext
is
available, so a possible refactor for that could be:
UserContext userContext = context.find(UserContext.class).orElse(UserContext.NO_USER_CONTEXT);
Agent constructors
Some constructors were removed from Agent
and LocalAgent
as well. These should not have been in use, but some of
them were public. For all of these, static methods exist that will retrieve the agent if given a Context
object.
An example would be LocalAgent(Local, UserContext)
and LocalAgent(Local, UserContext, Context)
, which can be
replaced by LocalAgent.getLocalAgent(context)
(and LocalAgent.getLocalAgent(Context.from(userContext))
if only
UserContext
is available).
Struts actions
Some expanded struts actions had a dedicated getUserContext()
method, which called
UserContextRetriever.getUserContext()
to obtain the UserContext
. This method has been removed and there is no
specific alternative for Context
. This should be refactored by calling ContextRetriever.getContext()
instead. This
will return a Context
object that contains the UserContext
object as well.
This applies to the CommandPerformer
, CommandPreparer
, DetailsPreparer
, FindAction
, ModifyAction
and
ProjectorAction
.
Deprecated agent methods
We added some deprecation of methods on the agents that take Long
database identifiers instead of a DataRef
. Though
these will not be immediately removed, it would be prudent to refactor them anyway. This applies to the following
methods currently:
Agent.getDataRef(Long)
Agent.getInfo(Long)
Agent.getDetails_old(Long)
Agent.getDetails(Long)
Since we wish to transition away from hardcoded methods for specific projections, it is also recommended to refactor
Agent.getDetails(DataRef)
. The following example is a possible refactorings for Agent.getDetails(Long)
. Refactoring
the other methods should follow the same pattern.
agent.getDetails(databaseId)
ProjectionRef projectionRef = new ProjectionRef()
.setDataRef(DataRef.from(databaseId))
.setProjection("details");
agent.getProjection(projectionRef);
Typed finders
Typed finders should in theory have little impact on existing implementations. The only exception is custom finders that
were previously not part of the application model and relied on reflection to find the implementation. These finders
should be added to the model as a new finder with the option
isCustomFinder
applied to it. This will provide an implementation stub in the FinderBean
class, as well as a FindDetails
class to
which the existing custom implementation can be migrated.
A transient legacy option legacy.typedFinders.disable
was introduced to revert to the old default behavior until
2024-03-01.