I have a mapped Entry ("entity") using Spring LDAP ODM. When I run unit tests with this class, I get a warning in the console upon initialization:
Mar 9, 2012 2:32:40 PM org.springframework.ldap.odm.core.impl.ObjectMetaData <init>
WARNING: The Entry class Superhero should be declared final
The mapped class looks like this:
#Entry(objectClasses = {"batman", "superman", "spiderman", "dontworryaboutthese"})
public class Superhero {
#Id
#JsonIgnore
private Name dn;
...
I can't find anything relevant via Google search regarding this warning. Here's the Spring code that logs it:
public ObjectMetaData(Class<?> clazz) {
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("Extracting metadata from %1$s", clazz));
}
// Get object class metadata - the #Entity annotation
Entry entity = (Entry)clazz.getAnnotation(Entry.class);
if (entity != null) {
// Default objectclass name to the class name unless it's specified
// in #Entity(name={objectclass1, objectclass2});
String[] localObjectClasses = entity.objectClasses();
if (localObjectClasses != null && localObjectClasses.length > 0 && localObjectClasses[0].length() > 0) {
for (String localObjectClass:localObjectClasses) {
objectClasses.add(new CaseIgnoreString(localObjectClass));
}
} else {
objectClasses.add(new CaseIgnoreString(clazz.getSimpleName()));
}
} else {
throw new MetaDataException(String.format("Class %1$s must have a class level %2$s annotation", clazz,
Entry.class));
}
// Check the class is final
if (!Modifier.isFinal(clazz.getModifiers())) {
LOG.warn(String.format("The Entry class %1$s should be declared final", clazz.getSimpleName()));
}
...
Any insight would be appreciated. I understand that declaring a class as final means it can't be extended, but why would Spring ODM care?
Security reason ?
Maybe by subclassing your entity, one could store other kind of LDAP entries in the directory, leading to unforseen behavior ?
Related
I'm currently migrating an JavaEE5 (WL 10.3.5) application to JavaEE 7 (WL 12.2.1) and I'm facing a strange issue.
The WebLogic 12c implemntation of method HttpSession.setAttribute(String, Object) does not replace the old object bound to the same string key by a new object if the objects are identical (identical according WL12c's implemntation).
After several tests, when you want to replace an object in session, WL12c compare hashCode if they are the same, it compare object whith equals(). If equals() return 'true' WL12c does NOT replace the object!
But there is no such information in the JavaEE 7 Api doc : setAttribute(String, Object)
Binds an object to this session, using the name specified. If an
object of the same name is already bound to the session, the object is
replaced.
No mention at all of " only if the object to replace is not identical according the hashCode and equals methods".
Example to test, suppose we have a class MyClass
import org.apache.commons.lang.builder.HashCodeBuilder;
class MyClass{
private Long id;
private String myProperty;
private static final int HASHCODE1 = -459751453;
private static final int HASHCODE2 = 981454267;
public MyClass(Long id, String myProperty) {
this.id = id;
this.myProperty = myProperty;
}
// Override equals based on the id only
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || this.getClass() != obj.getClass()) {
return false;
}
MyClass myClass = (MyClass) obj;
if (this.getId() != null) {
return this.getId().equals(myClass.getId());
}
return false;
}
// Override hashCode based only on id
#Override
public int hashCode() {
return new HashCodeBuilder(HASHCODE1, HASHCODE2).append(this.getId()).toHashCode();
}
/* Getters & Setters*/
}
And in a servlet we do
MyClass obj1 = new MyClass(1L, "prop1");
MyClass obj2 = new MyClass(1L, "prop2");
request.getSession().removeAttribute("key");
request.getSession().setAttribute("key", obj1);
request.getSession().setAttribute("key", obj2);
Two object with same id. In WL12c, the session will still contain obj1.
If I change the code (obj1.id = 2)
MyClass obj1 = new MyClass(1L, "prop1");
MyClass obj2 = new MyClass(2L, "prop2");
request.getSession().removeAttribute("key");
request.getSession().setAttribute("key", obj1);
request.getSession().setAttribute("key", obj2);
The session will contain obj2.
We didn't have this behaviour in WebLogic 10.3.5 which have the same doc. So, does WL12c not complying the Java EE 7 API ? If not why ?
Rem : by extension I think it's the same for the request and application attributes.
Edit 1: I tested this simple webapp (same war) in Tomcat 9 and in Wildfly 11. WebLogic 12.2.1 is the only one which don't replace the object in session.
Edit 2: I did not indicate it in my original post but I only found one topic about this problem and it was closed without any relevant answer:
HttpSession setAttribute doesn't always insert new object
Session management in Weblogic 12c got many updates. visit your Weblogic administration page to see how your session is being manged. JDBC-based session persistence may be the reasion.
Question:
How can I pass a string representing a table name to an NHibernate ClassMap?
Details:
I have several databases which are almost the same, with some minor variations in table and view names. I would like to be able to handle these variations via configuration parameters in my app.config file. For example, I could specify the table names for a particular configuration using the following custom section:
<tableNames>
<add key="logicalTable1" value="ACTUAL_TABLE_1"/>
<add key="logicalTable2" value="ACTUAL_TABLE_2"/>
</tablenames>
Now, if I load these config parameters at runtime, how do I get the table name into the ClassMap (i.e.,
public class MyClassMap : ClassMap<MyClass>
{
public class MyClassMap()
{
Table("ACTUAL_TABLE_1"); // <--- HERE I WANT Table(logicaTable1)
...
}
Note: I am using Ninject to inject ISessionFactory -- not sure if this matters.
Unless I am missing something, you could just use the ConfigurationManager class:
public class MyClassMap()
{
var table = ConfigurationManager.AppSettings["logicalTable2"];
Table(table);
...
}
Your project would need to reference the System.Configuration assembly.
Update:
Or use a "TableNameProvider" class:
public interface ITableNameProvider
{
string LogicalTable1 { get; }
}
public class TableNameProvider : ITableNameProvider
{
public string LogicalTable1 { get { return ConfigurationManager.AppSettings["logicalTable1"]; } }
}
I'm not sure about exactly how to do this with Ninject, but assuming its like other containers:
public class MyClassMap()
{
var provider = GetMyContainer().GetInstance<ITableProvider>();
var table = provider.LogicalTable1;
Table(table);
...
}
This way you would just need to change your TableNameProvider class.
I'm not sure if you could inject a MappingFactory or something into Fluent-NHibernate to handle mapping file dependencies and true injection. Something to look into.
I have project that need to reference to some web service, just say my reference is
service1Facade and service2Facade
both of them contain class name objectA
i must load objectA from service1Facade and use it as parameter in service2Facade.
but i got error
"value of type service1Facade.objectA cannot be converted to service2Facade.objectA"
how can i convert these object ?
what i have try but still not work:
group all reference into same folder, but .NET change its name into
objectA and objectA1
I copy every property of the property inside objectA, but still not working.
The functionality that is responsible for generating proxy classes based on your WSDL specification doesn't know (and it shouldn't know) that both your services use the same underlying type for objectA, and as I mentioned, no assumptions can be made regarding this since web services are meant to be decoupled from each other (from the consumer point of view).
I'd say your best option is to have your own proxy class (let's say ServiceProxyDTO) that can be used in both service #1 and #2. Something along the lines of:
public class ServiceProxyDTO
{
// Define properties from "objectA"
public ServiceProxyDTO() { }
public ServiceProxyDTO(service1Facade.ObjectA copyFrom)
{
// Copy state from "copyFrom"
}
public ServiceProxyDTO(service2Facade.ObjectA copyFrom)
{
// Copy state from "copyFrom"
}
public static implicit operator service1Facade.ObjectA(ServiceProxyDTO dto)
{
return new service1Facade.ObjectA() { /* Copy state back */ };
}
public static implicit operator service2Facade.ObjectA(ServiceProxyDTO dto)
{
return new service2Facade.ObjectA() { /* Copy state back */ };
}
public static implicit operator ServiceProxyDTO(service1Facade.ObjectA obj)
{
return new ServiceProxyDTO(obj);
}
public static implicit operator ServiceProxyDTO(service2Facade.ObjectA obj)
{
return new ServiceProxyDTO(obj);
}
}
With this code you can instantiate ServiceProxyDTO and pass it as parameter to both service #1 and #2 (as well as get the return values from both of these services).
Hope this helps.
On my service layer I have injected an UnitOfWork and 2 repositories in the constructor. The Unit of Work and repository have an instance of a DbContext I want to share between the two of them. How can I do that with Ninject ? Which scope should be considered ?
I am not in a web application so I can't use InRequestScope.
I try to do something similar... and I am using DI however, I need my UoW to be Disposed and created like this.
using (IUnitOfWork uow = new UnitOfWorkFactory.Create())
{
_testARepository.Insert(a);
_testBRepository.Insert(b);
uow.SaveChanges();
}
EDIT: I just want to be sure i understand… after look at https://github.com/ninject/ninject.extensions.namedscope/wiki/InNamedScope i though about my current console application architecture which actually use Ninject.
Lets say :
Class A is a Service layer class
Class B is an unit of work which take into parameter an interface (IContextFactory)
Class C is a repository which take into parameter an interface (IContextFactory)
The idea here is to be able to do context operations on 2 or more repository and using the unit of work to apply the changes.
Class D is a context factory (Entity Framework) which provide an instance (keep in a container) of the context which is shared between Class B et C (.. and would be for other repositories aswell).
The context factory keep the instance in his container so i don’t want to reuse this instance all the name since the context need to be disposed at the end of the service operaiton.. it is the main purpose of the InNamedScope actually ?
The solution would be but i am not sure at all i am doing it right, the services instance gonna be transcient which mean they actually never disposed ? :
Bind<IScsContextFactory>()
.To<ScsContextFactory>()
.InNamedScope("ServiceScope")
.WithConstructorArgument(
"connectionString",
ConfigurationUtility.GetConnectionString());
Bind<IUnitOfWork>().To<ScsUnitOfWork>();
Bind<IAccountRepository>().To<AccountRepository>();
Bind<IBlockedIpRepository>().To<BlockedIpRepository>();
Bind<IAccountService>().To<AccountService>().DefinesNamedScope("ServiceScope");
Bind<IBlockedIpService>().To<BlockedIpService>().DefinesNamedScope("ServiceScope");
UPDATE: This approach works against NuGet current, but relies in an anomaly in the InCallscope implementation which has been fixed in the current Unstable NuGet packages. I'll be tweaking this answer in a few days to reflect the best approach after some mulling over. NB the high level way of structuring stuff will stay pretty much identical, just the exact details of the Bind<DbContext>() scoping will work. (Hint: CreateNamedScope in unstable would work or one could set up the Command Handler as DefinesNamedScope. Reason I dont just do that is that I want to have something that composes/plays well with InRequestScope)
I highly recommend reading the Ninject.Extensions.NamedScope integration tests (seriously, find them and read and re-read them)
The DbContext is a Unit Of Work so no further wrapping is necessary.
As you want to be able to have multiple 'requests' in flight and want to have a single Unit of Work shared between them, you need to:
Bind<DbContext>()
.ToMethod( ctx =>
new DbContext(
connectionStringName: ConfigurationUtility.GetConnectionString() ))
.InCallScope();
The InCallScope() means that:
for a given object graph composed for a single kernel.Get() Call (hence In Call Scope), everyone that requires an DbContext will get the same instance.
the IDisposable.Dispose() will be called when a Kernel.Release() happens for the root object (or a Kernel.Components.Get<ICache>().Clear() happens for the root if it is not .InCallScope())
There should be no reason to use InNamedScope() and DefinesNamedScope(); You don't have long-lived objects you're trying to exclude from the default pooling / parenting / grouping.
If you do the above, you should be able to:
var command = kernel.Get<ICommand>();
try {
command.Execute();
} finally {
kernel.Components.Get<ICache>().Clear( command ); // Dispose of DbContext happens here
}
The Command implementation looks like:
class Command : ICommand {
readonly IAccountRepository _ar;
readonly IBlockedIpRepository _br;
readonly DbContext _ctx;
public Command(IAccountRepository ar, IBlockedIpRepository br, DbContext ctx){
_ar = ar;
_br = br;
_ctx = ctx;
}
void ICommand.Execute(){
_ar.Insert(a);
_br.Insert(b);
_ctx.saveChanges();
}
}
Note that in general, I avoid having an implicit Unit of Work in this way, and instead surface it's creation and Disposal. This makes a Command look like this:
class Command : ICommand {
readonly IAccountService _as;
readonly IBlockedIpService _bs;
readonly Func<DbContext> _createContext;
public Command(IAccountService #as, IBlockedIpServices bs, Func<DbContext> createContext){
_as = #as;
_bs = bs;
_createContext = createContext;
}
void ICommand.Execute(){
using(var ctx = _createContext()) {
_ar.InsertA(ctx);
_br.InsertB(ctx);
ctx.saveChanges();
}
}
This involves no usage of .InCallScope() on the Bind<DbContext>() (but does require the presence of Ninject.Extensions.Factory's FactoryModule to synthesize the Func<DbContext> from a straightforward Bind<DbContext>().
As discussed in the other answer, InCallScope is not a good approach to solving this problem.
For now I'm dumping some code that works against the latest NuGet Unstable / Include PreRelease / Instal-Package -Pre editions of Ninject.Web.Common without a clear explanation. I will translate this to an article in the Ninject.Extensions.NamedScope wiki at some stagehave started to write a walkthrough of this technique in the Ninject.Extensions.NamedScope wiki's CreateNamedScope/GetScope article.
Possibly some bits will become Pull Request(s) at some stage too (Hat tip to #Remo Gloor who supplied me the outline code). The associated tests and learning tests are in this gist for now), pending packaging in a proper released format TBD.
The exec summary is you Load the Module below into your Kernel and use .InRequestScope() on everything you want created / Disposed per handler invocation and then feed requests through via IHandlerComposer.ComposeCallDispose.
If you use the following Module:
public class Module : NinjectModule
{
public override void Load()
{
Bind<IHandlerComposer>().To<NinjectRequestScopedHandlerComposer>();
// Wire it up so InRequestScope will work for Handler scopes
Bind<INinjectRequestHandlerScopeFactory>().To<NinjectRequestHandlerScopeFactory>();
NinjectRequestHandlerScopeFactory.NinjectHttpApplicationPlugin.RegisterIn( Kernel );
}
}
Which wires in a Factory[1] and NinjectHttpApplicationPlugin that exposes:
public interface INinjectRequestHandlerScopeFactory
{
NamedScope CreateRequestHandlerScope();
}
Then you can use this Composer to Run a Request InRequestScope():
public interface IHandlerComposer
{
void ComposeCallDispose( Type type, Action<object> callback );
}
Implemented as:
class NinjectRequestScopedHandlerComposer : IHandlerComposer
{
readonly INinjectRequestHandlerScopeFactory _requestHandlerScopeFactory;
public NinjectRequestScopedHandlerComposer( INinjectRequestHandlerScopeFactory requestHandlerScopeFactory )
{
_requestHandlerScopeFactory = requestHandlerScopeFactory;
}
void IHandlerComposer.ComposeCallDispose( Type handlerType, Action<object> callback )
{
using ( var resolutionRoot = _requestHandlerScopeFactory.CreateRequestHandlerScope() )
foreach ( object handler in resolutionRoot.GetAll( handlerType ) )
callback( handler );
}
}
The Ninject Infrastructure stuff:
class NinjectRequestHandlerScopeFactory : INinjectRequestHandlerScopeFactory
{
internal const string ScopeName = "Handler";
readonly IKernel _kernel;
public NinjectRequestHandlerScopeFactory( IKernel kernel )
{
_kernel = kernel;
}
NamedScope INinjectRequestHandlerScopeFactory.CreateRequestHandlerScope()
{
return _kernel.CreateNamedScope( ScopeName );
}
/// <summary>
/// When plugged in as a Ninject Kernel Component via <c>RegisterIn(IKernel)</c>, makes the Named Scope generated during IHandlerFactory.RunAndDispose available for use via the Ninject.Web.Common's <c>.InRequestScope()</c> Binding extension.
/// </summary>
public class NinjectHttpApplicationPlugin : NinjectComponent, INinjectHttpApplicationPlugin
{
readonly IKernel kernel;
public static void RegisterIn( IKernel kernel )
{
kernel.Components.Add<INinjectHttpApplicationPlugin, NinjectHttpApplicationPlugin>();
}
public NinjectHttpApplicationPlugin( IKernel kernel )
{
this.kernel = kernel;
}
object INinjectHttpApplicationPlugin.GetRequestScope( IContext context )
{
// TODO PR for TrgGetScope
try
{
return NamedScopeExtensionMethods.GetScope( context, ScopeName );
}
catch ( UnknownScopeException )
{
return null;
}
}
void INinjectHttpApplicationPlugin.Start()
{
}
void INinjectHttpApplicationPlugin.Stop()
{
}
}
}
I am using entity framework and generic repository in my project.
Following is one of the method in my repository.
public IQueryable<TEntity> GetQuery<TEntity>() where TEntity : class
{
var entityName = GetEntityName<TEntity>();
return ((IObjectContextAdapter)DbContext).ObjectContext.CreateQuery<TEntity>(entityName);
}
when i consume this method in my WCF service I want to Include certain navigation properties of that DbSet.
For example,
List<Countries> GetCountries()
{
return this.repository.GetQuery<Countries>().Include("Cities").AsEnumerable().ToList();
}
this should return all countries with cities populated in the navigation properties.
Currently this gives an error saying The underlying connection was closed...
What changes you reckon to do to achieve this?
thanks
Start with rewriting your GetQuery method to use DbContext directly. the ObjectContext's GetQuery method is intended to use a SQL like syntax to query the data store.
You have a lot going on here you don't need. Since you're starting with a DbContext derived class, simply use dbContext.Set() to retrieve the DbSet for the entity type, then use the Include( path ) method on the DbSet object.
Repository method:
public IQueryable<TEntity> GetQuery<TEntity>( string includePath = null )
{
var dbSet = DbContext.Set<TEntity>();
if( !string.IsNullOrWhitespace( includePath ) )
{
return dbSet.Include( includePath );
}
return dbSet;
}
usage:
List<Countries> GetCountries()
{
return this.repository.GetQuery<Countries>( "Cities" ).ToList();
}
Upgrading to EF 5.0 code generator template has fixed the issue.