Spring not picking updated #Query value Using AOP - spring

JPA: Method
#Repository
public interface FloorRepository extends JpaRepository<TnFloor, Integer> {
#Query("select distinct tnFloor from TnFloor tnFloor where tnFloor.tnBuilding.buildingId in ?1")
public List<TnFloor> findByBuildingIds(List<Integer> buildingIds);
}
#Before("dataRolesPointCuts()")
public void beforeMethods(JoinPoint joinPoint) {
log.debug(" Before Advice Called " + joinPoint.toShortString());
String classArray[]=joinPoint.getTarget().getClass().getGenericInterfaces()[0].getTypeName().split("\\.");
String className = classArray[classArray.length-1];
String methodName = joinPoint.getSignature().getName();
String securedMethodName = className + "_" + methodName;
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication!=null)
{
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
String loggedINUserName = userDetails.getUsername();
Map<String, Map<String, String>> userRoleMap = usernameRoleMap.get(loggedINUserName);
TnMethodSecurityModel methodSecurity = methodSecurityMap.get(securedMethodName); // Replace with Map
if(methodSecurity!=null && methodSecurity.getTnMethodSecurityFilters()!=null && methodSecurity.getTnMethodSecurityFilters().size()>0)
{
Class<?> clazz =((Class<?>) joinPoint.getTarget().getClass().getGenericInterfaces()[0]);
try {
Method[] methods = clazz.getMethods();
Method method=null;
for(Method meth: methods )
{
if(meth.getName().equals(methodName))
{
method=meth;
break;
}
}
if(method == null)
return;
Query secParam = method.getAnnotation(Query.class);
String query=secParam.value();
String securityPredicate=Util.getSecuirtyPredicate(methodSecurity, userRoleMap);
try {
System.out.println("old MethodAnnotation = " + secParam.value());
Util. changeAnnotationValue(secParam, "value", query+" "+securityPredicate);
System.out.println("Asspect Query :: "+query);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("modified MethodAnnotation = " + secParam.value());
} catch ( SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
log.info("Executing with argument: {}", className + " " + methodName);
}
#SuppressWarnings("unchecked")
public static Object changeAnnotationValue(Annotation annotation, String key, Object newValue){
Object handler = Proxy.getInvocationHandler(annotation);
Field f;
try {
f = handler.getClass().getDeclaredField("memberValues");
} catch (NoSuchFieldException | SecurityException e) {
throw new IllegalStateException(e);
}
f.setAccessible(true);
Map<String, Object> memberValues;
try {
memberValues = (Map<String, Object>) f.get(handler);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
Object oldValue = memberValues.get(key);
if (oldValue == null || oldValue.getClass() != newValue.getClass()) {
throw new IllegalArgumentException();
}
memberValues.put(key,newValue);
return oldValue;
}
Output After Before Advice execution :
old MethodAnnotation = select distinct tnFloor from TnFloor tnFloor where tnFloor.tnBuilding.buildingId in ?1
modified MethodAnnotation = select distinct tnFloor from TnFloor tnFloor where tnFloor.tnBuilding.buildingId in ?1 (tnFloor.tnBuilding.buildingId IN (0,1,6))
But Final JPA is executing query before modification OUTPUT :.
select tnbuilding0_.building_id as building1_17_0_, tnbuilding0_.description as descript2_17_0_, tnbuilding0_.name as name3_17_0_, tnbuilding0_.site_id as site_id4_17_0_, tnsite1_.site_id as site_id1_65_1_, tnsite1_.description as descript2_65_1_, tnsite1_.email as email3_65_1_, tnsite1_.name as name4_65_1_, tnsite1_.url as url5_65_1_ from tn_building tnbuilding0_ inner join tn_site tnsite1_ on tnbuilding0_.site_id=tnsite1_.site_id where tnbuilding0_.building_id=?

Sorry for lecturing you, but... Annotation values are constants. You cannot change them. Your hacky way of trying to change their in-memory representations is maybe a nifty exercise, but bad design. If your application or aspect really rely on something like this, as a developer you should feel an instant urge to refactor instead.
As for why it is not working as you dreamed it up: You might expect that Spring reads annotations every time before executing an annotated method. But usually such frameworks scan annotations while wiring an application.
Simply do not use hard-coded constants (like in annotations) for things you might want to make more dynamic, be it by using AOP or by other means. If you do want to keep the query annotation but use AOP, I think you should try to hook into another component where the query is being parsed or sent to the database and modify it there.

Related

If and else block is executed during spring method annotated as Transactional

When I go to /confirmation-account link, in tomcat console I can see that if and else block is also executed. I can see:
print from ColorConsoleHelper.getGreenLog("loginView") and from ColorConsoleHelper.getGreenLog("confirmationAccountView")
This is really strange behavior. Why?
#RequestMapping(value = "/confirmation-account", method = RequestMethod.GET)
#Transactional
public ModelAndView displayConfirmationAccountPage(ModelAndView modelAndView, #RequestParam Map<String, String> requestParams) {
final int ACTIVE_USER = 1;
// find the user associated with the confirmation token
UserEntity userEntity = userService.findUserByConfirmationToken(requestParams.get("token"));
// this should always be non-null but we check just in case
if (userEntity!=null) {
// set the confirmation token to null so it cannot be used again
userEntity.setConfirmationToken(null);
// set enabled user
userEntity.setEnabled(ACTIVE_USER);
// save data: (token to null and active user)
saveAll(userEntity.getTrainings());
/*
RedirectAttributes won't work with ModelAndView but returning a string from the redirecting handler method works.
*/
modelAndView.addObject("successMessage", "Konto zostało pomyślnie aktywowane!");
modelAndView.setViewName("loginView");
ColorConsoleHelper.getGreenLog("loginView");
} else {
ColorConsoleHelper.getGreenLog("confirmationAccountView");
modelAndView.addObject("errorMessage", "Link jest nieprawidłowy...");
modelAndView.setViewName("confirmationAccountView");
}
return modelAndView;
}
public void saveAll(List<TrainingUserEntity> trainingUserEntityList) {
for ( TrainingUserEntity trainingUserEntity : trainingUserEntityList) {
entityManagerService.mergeUsingPersistenceUnitB(trainingUserEntity);
}
}
public void mergeUsingPersistenceUnitB(Object object) {
EntityManager entityManager = getEntityManagerPersistenceUnitB();
EntityTransaction tx = null;
try {
tx = entityManager.getTransaction();
tx.begin();
entityManager.merge(object);
tx.commit();
}
catch (RuntimeException e) {
if ( tx != null && tx.isActive() ) tx.rollback();
throw e; // or display error message
}
finally {
entityManager.close();
}
}
Below solution & explanation:
Because of /confirmation-account link is invoke twice, what is caused by dynamic proxy and #Transactional method annotated in controller It is mandatory to check how many displayConfirmationAccountPage method is invoked. It is workaround.
What do you think it is good or not to annotated #Transactional controller method?

Java Streams to iterate over a ResultSet object

I have the following code snippet
ResultSet rs = stmt.executeQuery();
List<String> userIdList = new ArrayList<String>();
while(rs.next()){
userIdList.add(rs.getString(1));
}
Can I make use of Java streams/Lambda expressions to perform this iteration instead of a while loop to populate the List?
You may create a wrapper for the ResultSet making it an Iterable. From there you can iterate as well as create a stream. Of course you have to define a mapper function to get the iterated values from the result set.
The ResultSetIterable may look like this
public class ResultSetIterable<T> implements Iterable<T> {
private final ResultSet rs;
private final Function<ResultSet, T> onNext;
public ResultSetIterable(ResultSet rs, CheckedFunction<ResultSet, T> onNext){
this.rs = rs;
//onNext is the mapper function to get the values from the resultSet
this.onNext = onNext;
}
private boolean resultSetHasNext(){
try {
hasNext = rs.next();
} catch (SQLException e) {
//you should add proper exception handling here
throw new RuntimeException(e);
}
}
#Override
public Iterator<T> iterator() {
try {
return new Iterator<T>() {
//the iterator state is initialized by calling next() to
//know whether there are elements to iterate
boolean hasNext = resultSetHasNext();
#Override
public boolean hasNext() {
return hasNext;
}
#Override
public T next() {
T result = onNext.apply(rs);
//after each get, we need to update the hasNext info
hasNext = resultSetHasNext();
return result;
}
};
} catch (Exception e) {
//you should add proper exception handling here
throw new RuntimeException(e);
}
}
//adding stream support based on an iteratable is easy
public Stream<T> stream() {
return StreamSupport.stream(this.spliterator(), false);
}
}
Now that we have our wrapper, you could stream over the results:
ResultSet rs = stmt.executeQuery();
List<String> userIdList = new ResultSetIterable(rs, rs -> rs.getString(1)).stream()
.collect(Collectors.toList())
}
EDIT
As Lukas pointed out, the rs.getString(1) may throw a checked SQLException, therefor we need to use a CheckedFunction instead of a java Function that would be capable of wrapping any checked Exception in an unchecked one.
A very simple implementation could be
public interface CheckedFunction<T,R> extends Function<T,R> {
#Override
default R apply(T t) {
try {
return applyAndThrow(t);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
R applyAndThrow(T t) throws Exception;
}
Alternatively you could use a library with such a function, i.e. jooλ or vavr
If using a third party library is an option, you could use jOOQ, which supports wrapping JDBC ResultSet in jOOQ Cursor types, and then stream them. For example, using DSLContext.fetchStream()
Essentially, you could write:
try (ResultSet rs = stmt.executeQuery()) {
DSL.using(con) // DSLContext
.fetchStream(rs) // Stream<Record>
.map(r -> r.get(0, String.class)) // Stream<String>
.collect(toList());
}
Disclaimer: I work for the vendor.
Try library: abacus-jdbc
List<String> userIdList = StreamEx.<String> rows(resultSet, 1).toList(); // Don't forget to close ResultSet
Or: If you want to close the ResultSet after toList.
StreamEx.<String> rows(resultSet, 1).onClose(() -> JdbcUtil.closeQuitely(resultSet)).toList();
Or: If you use the utility classes provided in abacus-jdbc:
String sql = "select user_id from user";
// No need to worry about closing Connection/Statement/ResultSet manually. It will be took care by the framework.
JdbcUtil.prepareQuery(dataSource, sql).stream(String.class).toList();
// Or:
JdbcUtil.prepareQuery(dataSource, sql).toList(String.class);
Disclaimer:I'm the developer of abacus-jdbc.

Add a custom parameter to Solr while using Spring Data Solr

Is it possible to add an additional parameter to a Solr query using Spring Data Solr that generates the following request?
"params": {
"indent": "true",
"q": "*.*",
"_": "1430295713114",
"wt": "java",
"AuthenticatedUserName": "user#domain.com"
}
I want to add a parameter needed by Apache Manifoldcf, AuthenticatedUserName and its value, alongside the other ones that are automatically populated by Spring Data Solr (q, wt).
Thank you,
V.
I managed to make it work by looking at the source code of the SolrTemplate class but I was wondering if there is a less intrusive solution.
public Page<Document> searchDocuments(DocumentSearchCriteria criteria, Pageable page) {
String[] words = criteria.getTitle().split(" ");
Criteria conditions = createSearchConditions(words);
SimpleQuery query = new SimpleQuery(conditions);
query.setPageRequest(page);
SolrQuery solrQuery = queryParsers.getForClass(query.getClass()).constructSolrQuery(query);
solrQuery.add(AUTHENTICATED_USER_NAME, criteria.getLoggedUsername());
try {
String queryString = this.queryParsers.getForClass(query.getClass()).getQueryString(query);
solrQuery.set(CommonParams.Q, queryString);
QueryResponse response = solrTemplate.getSolrServer().query(solrQuery);
List<Document> beans = convertQueryResponseToBeans(response, Document.class);
SolrDocumentList results = response.getResults();
return new SolrResultPage<>(beans, query.getPageRequest(), results.getNumFound(), results.getMaxScore());
} catch (SolrServerException e) {
log.error(e.getMessage(), e);
return new SolrResultPage<>(Collections.<Document>emptyList());
}
}
private <T> List<T> convertQueryResponseToBeans(QueryResponse response, Class<T> targetClass) {
return response != null ? convertSolrDocumentListToBeans(response.getResults(), targetClass) : Collections
.<T> emptyList();
}
public <T> List<T> convertSolrDocumentListToBeans(SolrDocumentList documents, Class<T> targetClass) {
if (documents == null) {
return Collections.emptyList();
}
return solrTemplate.getConverter().read(documents, targetClass);
}
private Criteria createSearchConditions(String[] words) {
return new Criteria("title").contains(words)
.or(new Criteria("description").contains(words))
.or(new Criteria("content").contains(words))
.or(new Criteria("resourcename").contains(words));
}

Spring SAML extension for multiple IDP'S

we are planning to use spring saml extension as SP into our application.
But the requirement with our application is we need to communicate with more than 1 IDP's
Could any one please provide me/direct me to the example where it uses multiple IDP's
I also would like to know spring saml extension supports what kind of IDPS like OPenAM/Ping federate/ADFs2.0 etc...
Thanks,
--Vikas
You need to have a class to maintain a list of metadatas of each Idp's - say you putting those metadatas in some list which will be shared across application by static method. I have something like below
NOTE- I am not copying all class as it is that I am having, so might came across minor issues which you should be able to resolve on your own,
public class SSOMetadataProvider {
public static List<MetadataProvider> metadataList() throws MetadataProviderException, XMLParserException, IOException, Exception {
logger.info("Starting : Loading Metadata Data for all SSO enabled companies...");
List<MetadataProvider> metadataList = new ArrayList<MetadataProvider>();
org.opensaml.xml.parse.StaticBasicParserPool parserPool = new org.opensaml.xml.parse.StaticBasicParserPool();
parserPool.initialize();
//Get XML from DB -> convertIntoInputStream -> pass below as const argument
InputStreamMetadataProvider inputStreamMetadata = null;
try {
//Getting list from DB
List companyList = someServiceClass.getAllSSOEnabledCompanyDTO();
if(companyList!=null){
for (Object obj : companyList) {
CompanyDTO companyDTO = (CompanyDTO) obj;
if (companyDTO != null && companyDTO.getCompanyid() > 0 && companyDTO.getSsoSettingsDTO()!=null && !StringUtil.isNullOrEmpty(companyDTO.getSsoSettingsDTO().getSsoMetadataXml())) {
logger.info("Loading Metadata for Company : "+companyDTO.getCompanyname()+" , companyId : "+companyDTO.getCompanyid());
inputStreamMetadata = new InputStreamMetadataProvider(companyDTO.getSsoSettingsDTO().getSsoMetadataXml());
inputStreamMetadata.setParserPool(parserPool);
inputStreamMetadata.initialize();
//ExtendedMetadataDelegateWrapper extMetadaDel = new ExtendedMetadataDelegateWrapper(inputStreamMetadata , new org.springframework.security.saml.metadata.ExtendedMetadata());
SSOMetadataDelegate extMetadaDel = new SSOMetadataDelegate(inputStreamMetadata , new org.springframework.security.saml.metadata.ExtendedMetadata()) ;
extMetadaDel.initialize();
extMetadaDel.setTrustFiltersInitialized(true);
metadataList.add(extMetadaDel);
logger.info("Loading Metadata bla bla");
}
}
}
} catch (MetadataProviderException | IOException | XMLParserException mpe){
logger.warn(mpe);
throw mpe;
}
catch (Exception e) {
logger.warn(e);
}
logger.info("Finished : Loading Metadata Data for all SSO enabled companies...");
return metadataList;
}
InputStreamMetadataProvider.java
public class InputStreamMetadataProvider extends AbstractReloadingMetadataProvider implements Serializable
{
public InputStreamMetadataProvider(String metadata) throws MetadataProviderException
{
super();
//metadataInputStream = metadata;
metadataInputStream = SSOUtil.getIdpAsStream(metadata);
}
#Override
protected byte[] fetchMetadata() throws MetadataProviderException
{
byte[] metadataBytes = metadataInputStream ;
if(metadataBytes.length>0)
return metadataBytes;
else
return null;
}
public byte[] getMetadataInputStream() {
return metadataInputStream;
}
}
SSOUtil.java
public class SSOUtil {
public static byte[] getIdpAsStream(String metadatXml) {
return metadatXml.getBytes();
}
}
After user request to fetch metadata for their company's metadata, get MetaData for entityId for each IdPs -
SSOCachingMetadataManager.java
public class SSOCachingMetadataManager extends CachingMetadataManager{
#Override
public ExtendedMetadata getExtendedMetadata(String entityID) throws MetadataProviderException {
ExtendedMetadata extendedMetadata = null;
try {
//UAT Defect Fix - org.springframework.security.saml.metadata.ExtendedMetadataDelegate cannot be cast to biz.bsite.direct.spring.app.sso.ExtendedMetadataDelegate
//List<MetadataProvider> metadataList = (List<MetadataProvider>) GenericCache.getInstance().getCachedObject("ssoMetadataList", List.class.getClassLoader());
List<MetadataProvider> metadataList = SSOMetadataProvider.metadataList();
log.info("Retrieved Metadata List from Cassendra Cache size is :"+ (metadataList!=null ? metadataList.size(): 0) );
org.opensaml.xml.parse.StaticBasicParserPool parserPool = new org.opensaml.xml.parse.StaticBasicParserPool();
parserPool.initialize();
if(metadataList!=null){
//metadataList.addAll(getAvailableProviders());
//metadataList.addAll(getProviders());
//To remove duplicate entries from list, if any
Set<MetadataProvider> hs = new HashSet<MetadataProvider> ();
hs.addAll(metadataList);
metadataList.clear();
metadataList.addAll(hs);
//setAllProviders(metadataList);
//setTrustFilterInitializedToTrue();
//refreshMetadata();
}
if(metadataList!=null && metadataList.size()>0) {
for(MetadataProvider metadataProvider : metadataList){
log.info("metadataProvider instance of ExtendedMetadataDelegate: Looking for entityId"+entityID);
SSOMetadataDelegate ssoMetadataDelegate = null;
ExtendedMetadataDelegateWrapper extMetadaDel = null;
// extMetadaDel.getDelegate()
if(metadataProvider instanceof SSOMetadataDelegate)
{ssoMetadataDelegate = (SSOMetadataDelegate) metadataProvider;
((InputStreamMetadataProvider)ssoMetadataDelegate.getDelegate()).setParserPool(parserPool);
((InputStreamMetadataProvider)ssoMetadataDelegate.getDelegate()).initialize();
ssoMetadataDelegate.initialize();
ssoMetadataDelegate.setTrustFiltersInitialized(true);
if(!isMetadataAlreadyExist(ssoMetadataDelegate))
addMetadataProvider(ssoMetadataDelegate);
extMetadaDel = new ExtendedMetadataDelegateWrapper(ssoMetadataDelegate.getDelegate() , new org.springframework.security.saml.metadata.ExtendedMetadata());
}
else
extMetadaDel = new ExtendedMetadataDelegateWrapper(metadataProvider, new org.springframework.security.saml.metadata.ExtendedMetadata());
extMetadaDel.initialize();
extMetadaDel.setTrustFiltersInitialized(true);
extMetadaDel.initialize();
refreshMetadata();
extendedMetadata = extMetadaDel.getExtendedMetadata(entityID);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(extendedMetadata!=null)
return extendedMetadata;
else{
return super.getExtendedMetadata(entityID);
}
}
private boolean isMetadataAlreadyExist(SSOMetadataDelegate ssoMetadataDelegate) {
boolean isExist = false;
for(ExtendedMetadataDelegate item : getAvailableProviders()){
if (item.getDelegate() != null && item.getDelegate() instanceof SSOMetadataDelegate) {
SSOMetadataDelegate that = (SSOMetadataDelegate) item.getDelegate();
try {
log.info("This Entity ID: "+ssoMetadataDelegate.getMetadata()!=null ? ((EntityDescriptorImpl)ssoMetadataDelegate.getMetadata()).getEntityID() : "nullEntity"+
"That Entity ID: "+that.getMetadata()!=null ? ((EntityDescriptorImpl)that.getMetadata()).getEntityID() : "nullEntity");
EntityDescriptorImpl e = (EntityDescriptorImpl) that.getMetadata();
isExist = this.getMetadata()!=null ? ((EntityDescriptorImpl)ssoMetadataDelegate.getMetadata()).getEntityID().equals(e.getEntityID()) : false;
if(isExist)
return isExist;
} catch (MetadataProviderException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
return isExist;
}
Add entry in ur Spring bean xml
<bean id="metadata" class="pkg.path.SSOCachingMetadataManager">
<constructor-arg name="providers" value="#{ssoMetadataProvider.metadataList()}">
</constructor-arg>
<property name="RefreshCheckInterval" value="-1"/>
<property name="RefreshRequired" value="false"/>
</bean>
Let me know incase of any concerns.
I have recently configured two IDPs for Spring SAML extension. Here we should follow one basic rule. For each IDP we want to add, we have to configure one IDP provider as well as one SP provider. We should configure the providers in a MetadataManager bean, CachingMetadataManager for example. Here are some code snippets to get the idea what I am trying to say about:
public void addProvider(String providerMetadataUrl, String idpEntityId, String spEntityId, String alias) {
addIDPMetadata(providerMetadataUrl, idpEntityId, alias);
addSPMetadata(spEntityId, alias);
}
public void addIDPMetadata(String providerMetadataUrl, String idpEntityId, String alias) {
try {
if (metadata.getIDPEntityNames().contains(idpEntityId)) {
return;
}
metadata.addMetadataProvider(extendedMetadataProvider(providerMetadataUrl, alias));
} catch (MetadataProviderException e1) {
log.error("Error initializing metadata", e1);
}
}
public void addSPMetadata(String spEntityId, String alias) {
try {
if (metadata.getSPEntityNames().contains(spEntityId)) {
return;
}
MetadataGenerator generator = new MetadataGenerator();
generator.setEntityId(spEntityId);
generator.setEntityBaseURL(baseURL);
generator.setExtendedMetadata(extendedMetadata(alias));
generator.setIncludeDiscoveryExtension(true);
generator.setKeyManager(keyManager);
EntityDescriptor descriptor = generator.generateMetadata();
ExtendedMetadata extendedMetadata = generator.generateExtendedMetadata();
MetadataMemoryProvider memoryProvider = new MetadataMemoryProvider(descriptor);
memoryProvider.initialize();
MetadataProvider metadataProvider = new ExtendedMetadataDelegate(memoryProvider, extendedMetadata);
metadata.addMetadataProvider(metadataProvider);
metadata.setHostedSPName(descriptor.getEntityID());
metadata.refreshMetadata();
} catch (MetadataProviderException e1) {
log.error("Error initializing metadata", e1);
}
}
public ExtendedMetadataDelegate extendedMetadataProvider(String providerMetadataUrl, String alias)
throws MetadataProviderException {
HTTPMetadataProvider provider = new HTTPMetadataProvider(this.bgTaskTimer, httpClient, providerMetadataUrl);
provider.setParserPool(parserPool);
ExtendedMetadataDelegate delegate = new ExtendedMetadataDelegate(provider, extendedMetadata(alias));
delegate.setMetadataTrustCheck(true);
delegate.setMetadataRequireSignature(false);
return delegate;
}
private ExtendedMetadata extendedMetadata(String alias) {
ExtendedMetadata exmeta = new ExtendedMetadata();
exmeta.setIdpDiscoveryEnabled(true);
exmeta.setSignMetadata(false);
exmeta.setEcpEnabled(true);
if (alias != null && alias.length() > 0) {
exmeta.setAlias(alias);
}
return exmeta;
}
You can find all answers to your question in the Spring SAML manual.
The sample application which is included as part of the product already includes metadata for two IDPs, use it as an example.
Statement on IDPs is included in chapter 1.2:
All products supporting SAML 2.0 in Identity Provider mode (e.g. ADFS
2.0, Shibboleth, OpenAM/OpenSSO, Efecte Identity or Ping Federate) can be used with the extension.

Suggest Generalization code for Calling Stored Procedure in Spring

public class TestProcedure extends StoredProcedure {
TestProcedure(BasicDataSource dataSource, String procName) {
this.setDataSource(dataSource);
this.setSql(procName);
this.declareParameter(new SqlParameter("#test", Types.INTEGER));
}
public List<Detail> executeProcedure(Integer studentId) {
Map inParams = new HashMap();
inParams.put("#test", studentId);
this.compile();
List<Detail> details = new ArrayList<Detail>();
try {
ArrayList<LinkedHashMap<String, Object>> list = (ArrayList<LinkedHashMap<String, Object>>) execute(inParams).get("#result-set-1");
for (LinkedHashMap<String, Object> linkedHashMap : list) {
Detail detail = new Detail();
detail.setStudent_id((Integer) linkedHashMap.get("student_id"));
detail.setStudent_name((String) linkedHashMap.get("student_name"));
detail.setStudent_marks((Double) linkedHashMap.get("student_marks"));
details.add(detail);
}
} catch (Exception e) {
System.out.println("Error Man : " + e);
}
return details;
}
}
Above is the code for calling SP through Spring Can anyone suggest a general structure for it .Some abstract class or interface ....
Check out JPA, iBatis, or Hibernate. All are ORM data access packages with implementations included in Spring. I use iBatis, but I'm sure any of the 3 are fine

Resources