broadleaf override controller method - broadleaf-commerce

I'm new on broadleaf.
I have problem, I wanted to obscure the method that removes my order in admin:
I create controller :
public class NewOrderController extends AdminBasicEntityController {
private static final Logger LOGGER = Logger.getLogger(NewOrderController.class);
protected static final String SECTION_KEY = "order";
#Override
protected String getSectionKey(Map<String, String> pathVars) {
if (super.getSectionKey(pathVars) != null) {
return super.getSectionKey(pathVars);
}
return SECTION_KEY;
}
#Override
#RequestMapping(
value = {"/{id}/delete"},
method = {RequestMethod.POST}
)
public String removeEntity(HttpServletRequest request, HttpServletResponse response, Model model, Map<String, String> pathVars, String id, EntityForm entityForm, BindingResult result, RedirectAttributes ra) throws Exception {
LOGGER.info("wywołanie nadpisane metody: " + NewOrderController.class.toString());
return "String";
}
}
in applicationContext-admin.xml
add :
All the time it calls me the not overwritten method.

When you create a controller, the bean must be in the servlet context, not in the root context. If you are modifying applicationContext-admin.xml then you are actually adding the bean to the root context.
Add your bean to applicationContext-servlet-admin.xml or add a new <component-scan> entry into applicationContext-servlet-admin.xml to scan your new bean.
One more thing: you likely do not want to override the entire AdminBasicEntityController and it looks like you just want to override /order/* methods. In that case, you should annotate your controller with #Controller and add an #RequestMapping for your section key like this:
#Controller
#RequestMapping("/" + SECTION_KEY)
public class NewOrderController extends AdminBasicEntityController {
private static final Logger LOGGER = Logger.getLogger(NewOrderController.class);
protected static final String SECTION_KEY = "order";
#Override
protected String getSectionKey(Map<String, String> pathVars) {
if (super.getSectionKey(pathVars) != null) {
return super.getSectionKey(pathVars);
}
return SECTION_KEY;
}
#Override
#RequestMapping(
value = {"/{id}/delete"},
method = {RequestMethod.POST}
)
public String removeEntity(HttpServletRequest request, HttpServletResponse response, Model model, Map<String, String> pathVars, String id, EntityForm entityForm, BindingResult result, RedirectAttributes ra) throws Exception {
LOGGER.info("wywołanie nadpisane metody: " + NewOrderController.class.toString());
return "String";
}
}

Related

Is this code thread safe with spring PostConstruct

I have done some tests on these two classes. Could someone please help to determine if these two classes are threadsafe? Could someone help to identify if not using concurrentHashMap, but use HashMap would it cause any concurrent issue. How can I make it more threadsafe? What is the best approach to testing it with concurrent testing?
I tested it with Hashmap only and it works fine. However, my scale of test is around 20 req/s for 2 mins.
Can anyone suggest if I should increase the req rate and try again or can point somewhere that must require fix.
#Component
public class TestLonggersImpl
implements TestSLongger {
#Autowired
YamlReader yamlReader;
#Autowired
TestSCatalog gSCatalog;
#Autowired
ApplicationContext applicationContext;
private static HashMap<String, TestLonggerImpl> gImplHashMap = new HashMap<>();
private static final Longger LONGER = LonggerFactory.getLongger(AbstractSLongger.class);
#PostConstruct
public void init() {
final String[] sts = yamlReader.getTestStreamNames();
for (String st : sts) {
System.out.println(st);
LONGER.info(st);
}
HashMap<String, BSCatalog> statsCatalogHashMap = gSCatalog.getCatalogHashMap();
for (Map.Entry<String, BSCatalog> entry : statsCatalogHashMap.entrySet()) {
BSCatalog bCatalog = statsCatalogHashMap.get(entry.getKey());
//Issue on creating the basicCategory
SProperties sProperties = yamlReader.getTestMap().get(entry.getKey());
Category category = new BasicCategory(sProperties.getSDefinitions(),
bCatalog.getVersion(),
bCatalog.getDescription(), new HashSet<>());
final int version = statsCatalogHashMap.get(entry.getKey()).getVersion();
getTestImplHashMap().put(entry.getKey(),
applicationContext.getBean(TestLonggerImpl.class, category,
entry.getKey(),
version));
}
}
#Override
public void logMessage(String st, String message) {
if (getTestImplHashMap() != null && getTestImplHashMap().get(st) != null) {
getTestImplHashMap().get(st).log(message);
}
}
#VisibleForTesting
static HashMap<String, TestLonggerImpl> getTestImplHashMap() {
return gImplHashMap;
}
}
*** 2nd class
#Component
public class GStatsCatalog {
#Autowired
YamlReader yamlReader;
private static HashMap<String, BStatsCatalog> stCatalogHashMap = new HashMap<>();
#PostConstruct
public void init() {
String[] streams = yamlReader.getGSNames();
for (String stream : streams) {
BStatsCatalog bCatalog = new BStatsCatalog();
SProperties streamProperties = yamlReader.getGMap().get(stream);
bCatalog.setSName(stream);
int version = VERSION;
try {
version = Integer.parseInt(streamProperties.getVersion());
} catch (Exception e) {
System.out.println(e.getMessage());
}
bCatalog.setVersion(version);
bCatalog.setDescription(streamProperties.getDescription());
stCatalogHashMap.put(stream, bCatalog);
}
}
public static HashMap<String, BStatsCatalog> getCatalogHashMap() {
return stCatalogHashMap;
}
public void setYamlReader(YamlReader yamlReader) {
this.yamlReader = yamlReader;
}
}
I think the methods under #postconstruct are threadsafe. It only runs once after the bean created in the whole lifecircle of the bean.

Model mapper mapping Map<String,Object> to class which extends another generic class not working for list field

I am trying to create my custom configuration object from Map using model mapper. Everything gets mapped properly excepts the fields property which is coming fro Generic super class.
My target object is
public class ADParserConfig extends CustomParserConfig<ADParserConfigField> {
private String pattern;
public String getPattern() {
return pattern;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
}
This extends generic class CustomParserConfig
public class CustomParserConfig<T extends CustomParserConfigField> {
protected List<T> fields;
protected String timeStampField;
public List<T> getFields() {
return fields;
}
public void setFields(List<T> fields) {
this.fields = fields;
}
public String getTimeStampField() {
return timeStampField;
}
public void setTimeStampField(String timeStampField) {
this.timeStampField = timeStampField;
}
}
Where CustomParserConfigField is
public class CustomParserConfigField {
protected String name;
protected Integer index;
protected String type;
protected String format;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getIndex() {
return index;
}
public void setIndex(Integer index) {
this.index = index;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
}
I am trying to map Map using below function
ADParserConfig adParserConfig = getConfig(map,ADParserConfig.class);
public <T extends CustomParserConfig> T getConfig(Map<String,Object> configObject, Class<T> classType){
ModelMapper modelMapper = new ModelMapper();
return modelMapper.map(configObject,classType);
}
Everything excepts fields gets mapped properly for the below map.
{fields=[{name=timeStamp, type=timestamp, format=dd/mm/yyyy HH:MM:SS a}, {name=logName, type=string}], pattern=(?<timeStamp>\d{2}\/\d{2}\/\d{4}\s\d{2}:\d{2}:\d{2}\s[AMPMampm]{2})?\s(LogName=(?<logName>[\w\s\W]+))?\sSourceName=(?<sourceName>[\w\s\W]+)\sEventCode=(?<eventCode>[0-9]*), timeStampField=timestamp}
Please help. Why is issue happens only for fields object ? Do I need to specify something else in mapper configurations ?
It looks like a bug and it had been fixed by #370

HashMap is empty after deserialization with Jersey and Jackson

I have a REST web service using Jersey 1.17.1 and Jackson 1.9.2.
The API looks like this:
public class PlayerRequest {
private String language;
private String playerId;
private Map<String, String> params;
}
When this service is called by other component, the params map is received empty:
PlayerRequest [language=null, playerId=100036343, params={}]
Original request from other component:
PlayerRequest [language=null, playerId=100036343, params={context=mobile, countrycode=SE, partnerskin=8, locale=en_GB, ipaddress=62.209.186.13}]
Why is the HashMap empty after the deserialization?
In your PlayerRequest class, create a method annotated with #JsonAnySetter, as following:
#JsonAnySetter
public void set(String key, String value) {
params.put(key, value);
}
This method works as a fallback handler for all unrecognized properties found in the JSON content.
To use the above mentioned approach, ensure the params field is being initialized:
private Map<String, String> params = new HashMap<String, String>();
So, your PlayerRequest class would be like:
public class PlayerRequest {
private String language;
private String playerId;
private Map<String, String> params = new HashMap<String, String>();
public PlayerRequest() { }
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getPlayerId() {
return playerId;
}
public void setPlayerId(String playerId) {
this.playerId = playerId;
}
public Map<String, String> getParams() {
return params;
}
public void setParams(Map<String, String> params) {
this.params = params;
}
#JsonAnySetter
public void set(String key, String value) {
params.put(key, value);
}
}
Fixed by implementing and adaptor(javax.xml.bind.annotation.adapters.XmlAdapter) and annotated the map in api with #XmlJavaTypeAdapter

#CacheEvict with key="#id" throws NullPointerException

I'm trying to use Spring Caching annotations #Cacheable and #CacheEvict together with the GuavaCacheManager.
I've created a test case with these two tests:
cachesById - verifies that two invocations to a method annotatted with #Cacheable returns the same object
evict - verifies that two different instances are returned if a method annotated with #CacheEvict is called in-between those two invocations
Both work fine when i don't specify a key for #CacheEvict, however when I do i get the following exception:
java.lang.NullPointerException
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:210)
at com.google.common.cache.LocalCache$LocalManualCache.invalidate(LocalCache.java:4764)
at org.springframework.cache.guava.GuavaCache.evict(GuavaCache.java:135)
at org.springframework.cache.interceptor.AbstractCacheInvoker.doEvict(AbstractCacheInvoker.java:95)
at org.springframework.cache.interceptor.CacheAspectSupport.performCacheEvict(CacheAspectSupport.java:409)
at org.springframework.cache.interceptor.CacheAspectSupport.processCacheEvicts(CacheAspectSupport.java:392)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:362)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:299)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
at com.myorg.caching.CacheTest$Repo$$EnhancerBySpringCGLIB$$eed50f3e.update(<generated>)
at com.myorg.caching.CacheTest.evict(CacheTest.java:50)
This can be reproduced by executing the below test.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(
classes = { Repo.class, CacheTest.SpringConfig.class },
loader = AnnotationConfigContextLoader.class)
public class CacheTest {
private static final String CACHE_NAME = "cacheName";
#Inject
private Repo repo;
#Test
public void cachesById() {
Entity aResult1 = repo.getEntity(1);
Entity aResult2 = repo.getEntity(1);
assertEquals(aResult1.getId(), aResult2.getId());
assertSame(aResult1, aResult2);
}
#Test
public void evict() {
Entity aResult1 = repo.getEntity(1);
repo.update(aResult1);
Entity aResult2 = repo.getEntity(1);
assertEquals(aResult1.getId(), aResult2.getId());
assertNotSame(aResult1, aResult2);
}
/** Mock repository/entity classes below. */
#Component
public static class Repo {
#Cacheable(value = CACHE_NAME, key = "#id")
public Entity getEntity(int id) {
return new Entity(id);
}
#CacheEvict(value = CACHE_NAME, key = "#id")
public void update(Entity e) {
}
}
public static class Entity {
private int id;
public Entity(int id) {
super();
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
/** Guava Cachemanager Spring configuration */
#Configuration
#EnableCaching
public static class SpringConfig {
#Bean
public CacheManager cacheManager() {
GuavaCacheManager manager = new GuavaCacheManager(CACHE_NAME);
manager.setCacheBuilder(CacheBuilder.newBuilder().expireAfterWrite(
1, TimeUnit.MINUTES).recordStats());
return manager;
}
}
}
However the test passes if I change
#CacheEvict(value = CACHE_NAME, key = "#id")
public void update(Entity e) {
into:
#CacheEvict(value = CACHE_NAME)
public void update(Entity e) {
..but then I'm missing the point where I need to specify the cache key for Entity. Does anyone know what I'm missing?
Thanks!
You have to fix you component class from
#Component
public static class Repo {
#Cacheable(value = CACHE_NAME, key = "#id")
public Entity getEntity(int id) {
return new Entity(id);
}
#CacheEvict(value = CACHE_NAME, key = "#id")
public void update(Entity e) {
}
}
to
#Component
public static class Repo {
#Cacheable(value = CACHE_NAME, key = "#id")
public Entity getEntity(int id) {
return new Entity(id);
}
#CacheEvict(value = CACHE_NAME, key = "#e?.id")
public void update(Entity e) {
}
}
Why? In getEntity method you're caching an Entity object using int id, you have to pass the same int id into the #CacheEvict annotated method. You don't have to change method's signature - by using SPEL you can "get into" entity and use its id field.
Hope I helped.

#XmlPath(".") conflicts with #XmlAdapter

having this Jaxb Xml definition, i try to remove the Map Elements Wrapper by adding #XmlPath(".") but it cause exception during the unmarchaling
#XmlRootElement
public abstract class ViewElement{
#XmlJavaTypeAdapter(value=EventAdapter.class)
public Map<Event, String> getEvents() {
}
private transient Class entityType;
public Class getEntityType() {
return entityType;
}
}
And the EventAdapter is
public class EventAdapter extends XmlAdapter<EventAdapter.AdaptedMap, Map<Event, String>> {
public static class AdaptedMap {
#XmlVariableNode("key")
List<AdaptedEntry> entries = new ArrayList<AdaptedEntry>();
}
public static class AdaptedEntry {
#XmlTransient
public String key;
#XmlValue
public String value;
}
.....
}
my output was
<element>
<events>
<onCellEdit>do some thing<onCellEdit>
</events>
<entityType>com.agitech.erp.model.erp.ErpFolder</entityType>
<element>
I try to remove the <events> tag by adding #XmlPath(".")
#XmlPath(".")
#XmlJavaTypeAdapter(value=EventAdapter.class)
public Map<Event, String> getEvents() {
}
The output is good
<element>
<onCellEdit>do some thing<onCellEdit>
<entityType>com.agitech.erp.model.erp.ErpFolder</entityType>
<element>
but the unmarchaling faileds
Caused by: Exception [EclipseLink-3002] (Eclipse Persistence Services - 2.6.0.v20140809-296a69f): org.eclipse.persistence.exceptions.ConversionException
Exception Description: The object [], of class [class java.lang.String], from mapping [org.eclipse.persistence.oxm.mappings.XMLDirectMapping[entityType-->view.entityType/text()]] with descriptor [XMLDescriptor(com.agitech.erp.view.BeanView --> [DatabaseTable(view), DatabaseTable(viewFrame), DatabaseTable(viewElement)])], could not be converted to [class java.lang.Class].
Internal Exception: java.lang.ClassNotFoundException:
at org.eclipse.persistence.exceptions.ConversionException.couldNotBeConvertedToClass(ConversionException.java:95)
at org.eclipse.persistence.internal.helper.ConversionManager.convertObjectToClass(ConversionManager.java:446)
Debuging Jaxb bring me to the line
org.eclipse.persistence.internal.oxm.XMLDirectMappingNodeValue
public void endElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord) {
...
line 205 unmarshalRecord.setAttributeValue(convertedValue, xmlDirectMapping);
}
During the unmarchaling of entityType value, the UnmarshalRecordImpl.currentObj contains the EventAdapter instead of the parent element
I modify org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl
public XPathNode getNonAttributeXPathNode(String namespaceURI, String localName, String qName, Attributes attributes) {
....
if(null == resultNode && null == nonPredicateNode) {
// ANY MAPPING
resultNode = xPathNode.getAnyNode();
// by default it return the EventAdapter, changing it to NULL fix my problem
}
....
}
Not a safe solution
I have been able to reproduce the issue that you are seeing, but haven't yet worked out the cause. You can use the following bug to track the progress on this issue:
http://bugs.eclipse.org/457169
After trying a lot of things, I was able to find a workaround for this issue. I thought of posting here the same so it can be helpful to someone else in the future. The lead has confirmed the issue around 5 years ago but seems like they have not fixed it and I was facing a similar issue.
Basically, we can use the beforeMarshal and afterUnmarshal methods to change the values in the fields.
You need to create a field List<Object> with #XmlAnyElement(lax=true) along with Map<String,Object>.
Remove the #XmlPath(".") and the XMLAdapter class.
Mark the field Map<String, Object> with #XmlTransient.
Now within the beforeMarshal and afterMarshal fields, you can exchange the data. During the unmarshal in beforeunmarshal, all the unknown field values will be present within the List<Object> loop over it and add it to the Map<String, Object>.
Similarly during the marshaling, you can move the values Map<String, Object> to List<Object> by creating the DOM elements.
Marshaling all values are added to root as DOM Elements are present and during Unmarshaling known values are read first and then-unknown values are stored within List<Object> due to #XmlAnyElement.
I have created an example using the Customer class, you can modify it accordingly for your need.
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "isA")
#JsonInclude(Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
#XmlRootElement(name = "Customer")
#XmlType(name = "Customer", propOrder = {"name", "age", "otherElements"})
#XmlAccessorType(XmlAccessType.FIELD)
#Getter
#Setter
#AllArgsConstructor
#ToString
#NoArgsConstructor
public class Customer {
#XmlTransient
private String isA;
private String name;
private String age;
#XmlAnyElement(lax = true)
#JsonIgnore
private List<Object> otherElements = new ArrayList<>();
#JsonIgnore
#XmlTransient
private Map<String, Object> userExtensions = new HashMap<>();
#JsonAnyGetter
#JsonSerialize(using = CustomExtensionsSerializer.class)
public Map<String, Object> getUserExtensions() {
return userExtensions;
}
#JsonAnySetter
public void setUserExtensions(String key, Object value) {
userExtensions.put(key, value);
}
private void beforeMarshal(Marshaller m) throws ParserConfigurationException {
System.out.println("Before Marshalling User Extension: " + userExtensions);
ExtensionsModifier extensionsModifier = new ExtensionsModifier();
otherElements = extensionsModifier.Marshalling(userExtensions);
System.out.println("Before Marshalling Final Other Elements " + otherElements);
userExtensions = new HashMap<>();
}
private void afterUnmarshal(Unmarshaller m, Object parent) throws ParserConfigurationException {
System.out.println("After Unmarshalling : " + otherElements);
ExtensionsModifier extensionsModifier = new ExtensionsModifier();
userExtensions = extensionsModifier.Unmarshalling(otherElements);
otherElements = new ArrayList();
}
}
You can refer the creation of DOM ELEMENTS here:https://stackoverflow.com/a/24239105/7584240
You can refer my complete answer here: https://stackoverflow.com/a/67923216/7584240

Resources