|
|
|
[
Permlink
| « Hide
]
Wouter de Vaal - 19/Oct/07 09:34 AM
Check out the output from class C, I think this is unexpected behaviour.
Note: in the code I used some different names, but I think my point should be clear from the code.
Wouter, I've commmited a fix for the issue along with some tests.
Note that for this to work, you either require the same proxy setup or you need the objects to implement equals. Very important, make sure that the interface/classes used to create the proxy declare the 'equals' method otherwise the 'backing' equals method will not be called. Hi Costin,
I've tried the same code as I attached to this bug with the latest rc1 snapshot, but I still get the same result, the two referenced beans are not equal. The object that is reference has hashCode/equals methods and they are not called. It is just simply the "A" class and it does not implement any additional interfaces.. Take a look at the tests and the FAQ - it depends whether the hashCode/equals are proxied or not. If they aren't then then they are not called and thus the proxy infrastructure equality will apply.
I don't see any new FAQ entry online (where should I look?)
This is the class that is being proxied, it doesn't get any simpler than that, how else can I make sure equals/hash are exposed? They are public methods of a class that just extends Object and nothing else: package a; public class A { private String a; public void setA(String a) { this.a = a; } @Override public String toString() { return a; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((a == null) ? 0 : a.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final A other = (A) obj; if (a == null) { if (other.a != null) return false; } else if (!a.equals(other.a)) return false; return true; } } application context: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:osgi="http://www.springframework.org/schema/osgi" xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <bean id="a" class="a.A" p:a="a"> </bean> <osgi:service id="aOsgi" ref="a" interface="a.A" /> </beans> referencing app context snippets: <osgi:reference id="a" interface="a.A" cardinality="1..1" /> Could you please check out this issue again? AFAIK it is still broken.
In the example I attached and posted on, I updated the equals/hash on A so it uses the system identity. Also I added a simple system.out to see whether it is ever called. @Override public int hashCode() { System.err.println("A HASH CALLED"); return System.identityHashCode(this); } @Override public boolean equals(Object obj) { System.err.println("A EQUALS CALLED"); if (this == obj) return true; if (obj == null) return false; final A other = (A) obj; return hashCode() == other.hashCode(); } I tried the following afterPropertiesSet in the C bundle: @SuppressWarnings("nls") @Override public void afterPropertiesSet() throws Exception { A c = b.getCola().iterator().next(); System.out.println("I expect true here: " + b.getCola().contains(a)); System.out.println("Calling equals directly on the two a objects: " + a.equals(b.getCola().iterator().next())); System.out.println("System ids: " + b.getCola().iterator().next().getServiceIdentity()); System.out.println("System ids: " + a.getServiceIdentity()); System.out.println("Calling the hashes: " + a.hashCode() + "--" + b.getCola().iterator().next().hashCode()); //get a and b through "regular" osgi references (activator finds the beans through the bean context) A aa = Activator.getA(); B bb = Activator.getB(); System.out.println("I expect true here: " + bb.getCola().contains(aa)); System.out.println("Calling equals directly on the two a objects: " + aa.equals(bb.getCola().iterator().next())); } This is the output:I expect true here: false Calling equals directly on the two a objects: false System ids: 17855236 System ids: 17855236 Calling the hashes: 448141710--448141710 I expect true here: false Calling equals directly on the two a objects: false and I only get 1 systemout line for A EQUALS CALLED and HASHCODE twice (which is triggered by the calls on the osgi reference). So the only real time the equals/hash on A is called, is when I called tried to test whether a is in the collection of b, when I fetched them through osgi directly. All in all, I don't think this bug should have been closed Hi,
I have bumped into another real-life scenario: Bundle a declares a javax.sql.DataSource service. Bundle b has a service that uses JdbcTemplate with a proxy of that DataSource Bundle c has a service that call the service in bundle b and uses a JdbcTemplate with another proxy to the same DataSource, these call are done within a single PlatformTransactionManager session (a DataSourceTransactionManage). The transaction manager uses the DataSource object as a key to store DataSource-connection mappings, so it depends on object equality to pick up the correct connection within a transaction. We did do a workaround on this by extending the DataSource interface with equals/hashcode methods and extended our used DataSource (jakarta commons dbcp BasicDataSource) and adding system identity implementation to the new subclass. See all this in the following bug report related to the transaction manager: http://jira.springframework.org/browse/SPR-4461 We believe there can be no generic solution to the problem, because even when you add equals/hash to the exported interface, the equals implementation may only rely on information exposed through this interface, so no internal state can be used in equality. However it may be nice do add something of an addendum describing these issues and suggesting sulutions as described above. Hi, I have experienced simelar problem, and finally I found that same classes were packaged in more than one bundle, so as different classloaders return un-equal java.lang.Class instance to (in fact) same class.
After removing duplicate deployment, share these class through Export-Package:, then things go well. Good Luck, yours Geng. I'm running in to the same problem but with JPA. Spring JPA uses the EntityManagerFactory as the key for the TransactionSynchronizationManager. This is problematic if you have the following bundle configuration:
- Bundle 1: Contains and exports the EntityMangerFactory and JpaTransactionManager - Bundle 2: Imports EMF and JpaTxMgr and contains a repository and the PersistenceAnnotationBeanPostProcessor At runtime, the JpaTransactionManager creates the transaction and binds an entity manager holder to the TransactionSynchronizationManager using the EntityManagerFactory as the key. But when the EntityManager proxy that is injected in to the repository goes to retrieve the entity manager holder, it can't find it due to the EntityManagerFactory instance being a proxy. Guys, M2 will address this problem by implementing InfrastructureProxy new in Spring 2.5.4. I'll commit the code today (note that Spring 2.5.4-SNAPSHOT will be used).
Guys, since I haven't got any reports so far I'm closing the issue.
If you still encounter issue or think there is something extra that we can try, please reopen it or raise another one. Thanks, |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||