SkuAttributes in Sku Object in broadleaf is not coming in response - broadleaf-commerce

In broadleaf, I can see that the sku contains the skuAttributes. But when I try to invoke the product info using the endpoint /catalog/product/{id}.. am do not see the skuAttributes coming in the api response. How can I get those sku attributes values as part of the response?

You will need to override the SkuWrapper bean in an #Configuration class. Example:
#Configuration
public class ApiWrapperOverrides {
#Bean
#Scope("prototype")
public MySkuWrapper blSkuWrapper() {
return new MySkuWrapper();
}
}
public class MySkuWrapper extends SkuWrapper {
#XmlElement(name = "skuAttribute")
#XmlElementWrapper(name = "skuAttributes")
protected List<SkuAttributeWrapper> skuAttributes = new ArrayList<>();
#Override
public void wrapDetails(Sku model, HttpServletRequest request) {
super.wrapDetails(sku, request);
if (model.getSkuAttributes() != null && !model.getSkuAttributes().isEmpty()) {
for (Map.Entry<String, SkuAttribute> entry : model.getSkuAttributes().entrySet()) {
wrapper.wrapSummary(entry.getValue(), request);
skuAttributes.add(wrapper);
}
}
}
}

Related

Mocking a method inside my test class

Android Studio 2.3
I have the following method I want to test inside my model class:
public class RecipeListModelImp implements RecipeListModelContract {
private Subscription subscription;
private RecipesAPI recipesAPI;
private RecipeSchedulers recipeSchedulers;
#Inject
public RecipeListModelImp(#NonNull RecipesAPI recipesAPI, #NonNull RecipeSchedulers recipeSchedulers) {
this.recipesAPI = Preconditions.checkNotNull(recipesAPI);
this.recipeSchedulers = Preconditions.checkNotNull(recipeSchedulers);
}
#Override
public void getRecipesFromAPI(final RecipeGetAllListener recipeGetAllListener) {
subscription = recipesAPI.getAllRecipes()
.subscribeOn(recipeSchedulers.getBackgroundScheduler())
.observeOn(recipeSchedulers.getUIScheduler())
.subscribe(new Subscriber<List<Recipe>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
recipeGetAllListener.onRecipeGetAllFailure(e.getMessage());
}
#Override
public void onNext(List<Recipe> recipe) {
recipeGetAllListener.onRecipeGetAllSuccess(recipe);
}
});
}
#Override
public void shutdown() {
if(subscription != null && !subscription.isUnsubscribed()) {
subscription.unsubscribe();
}
}
}
Inside my test class I am testing like this:
public class RecipeListModelImpTest {
#Mock Subscription subscription;
#Mock RecipesAPI recipesAPI;
#Mock RecipeListModelContract.RecipeGetAllListener recipeGetAllListener;
#Mock List<Recipe> recipes;
#Inject RecipeSchedulers recipeSchedulers;
private RecipeListModelContract recipeListModel;
#Before
public void setup() {
TestBusbyComponent testBusbyComponent = DaggerTestBusbyComponent.builder()
.mockRecipeSchedulersModule(new MockRecipeSchedulersModule())
.build();
testBusbyComponent.inject(RecipeListModelImpTest.this);
MockitoAnnotations.initMocks(RecipeListModelImpTest.this);
recipeListModel = new RecipeListModelImp(recipesAPI, recipeSchedulers);
}
#Test(expected = NullPointerException.class)
public void testShouldThrowExceptionOnNullParameter() {
recipeListModel = new RecipeListModelImp(null, null);
}
#Test
public void testRecipeListModelShouldNotBeNull() {
assertNotNull(recipeListModel);
}
#Test
public void testShouldGetRecipesFromAPI() {
when(recipesAPI.getAllRecipes()).thenReturn(Observable.just(recipes));
recipeListModel.getRecipesFromAPI(recipeGetAllListener);
verify(recipesAPI, times(1)).getAllRecipes();
verify(recipeGetAllListener, times(1)).onRecipeGetAllSuccess(recipes);
verify(recipeGetAllListener, never()).onRecipeGetAllFailure(anyString());
}
#Test
public void testShouldFailToGetRecipesFromAPI() {
when(recipesAPI.getAllRecipes())
.thenReturn(Observable.<List<Recipe>>error(
new Throwable(new RuntimeException("Failed to get recipes"))));
recipeListModel.getRecipesFromAPI(recipeGetAllListener);
verify(recipesAPI, times(1)).getAllRecipes();
verify(recipeGetAllListener, times(1)).onRecipeGetAllFailure(anyString());
verify(recipeGetAllListener, never()).onRecipeGetAllSuccess(recipes);
}
#Test
public void testShouldShutdown() {
when(subscription.isUnsubscribed()).thenReturn(false);
final Field subscriptionField;
try {
subscriptionField = recipeListModel.getClass().getDeclaredField("subscription");
subscriptionField.setAccessible(true);
subscriptionField.set(recipeListModel, subscription);
} catch(NoSuchFieldException e) {
e.printStackTrace();
}
catch(IllegalAccessException e) {
e.printStackTrace();
}
recipeListModel.shutdown();
verify(subscription, times(1)).unsubscribe();
}
}
However, the problem is the Subscription in my model class is always null so will never enter the if blook. Is there any way to test this with using Mockito or spys?
Many thanks for any suggestions,
You should for testing recipeListModel class, where you have shutdown() method , set mock into this class.
If you don't have set method for subscription in recipeListModel , or constructor param.... ),you can set mock object with reflection like :
#Test
public void testShouldShutdown() {
Subscription subscription = mock(Subscription.class);
when(subscription.isUnsubscribed()).thenReturn(false);
Field subscriptionField = recipeListModel.getClass().getDeclaredField("subscription");
subscriptionField.setAccessible(true);
subscriptionField.set(recipeListModel, subscriptionMock);
recipeListModel.shutdown();
verify(subscription, times(1)).unsubscribe();
}
after your update :
if you can't change way of creation , you should mock it like (full way of creation) , i don't know your api , so it's just idea:
Subscription subscription = mock(Subscription.class);
when(subscription.isUnsubscribed()).thenReturn(false);
// preparation mock for create Subscription
//for recipesAPI.getAllRecipes()
Object mockFor_getAllRecipes = mock(....);
when(recipesAPI.getAllRecipes()).thenReturn(mockFor_getAllRecipes );
//for subscribeOn(recipeSchedulers.getBackgroundScheduler())
Object mockFor_subscribeOn = mock();
when(mockFor_getAllRecipes.subscribeOn(any())).thenReturn(mockFor_subscribeOn);
//for .observeOn(recipeSchedulers.getUIScheduler())
Object mockFor_observeOn = mock();
when(mockFor_subscribeOn .observeOn(any())).thenReturn(observeOn);
// for .subscribe
when(observeOn.subscribe(any()).thenReturn(subscription);

broadleaf override controller method

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";
}
}

AmbiguousMatchException exception in ServiceStack?

PFB my code.
namespace ManualCSharpe
{
public class MyServices : Service
{
[Route("/L/hello/")] //RequestDTO one
public class HelloL
{
public string Name { get; set; }
}
[Route("/H/hello/")] //RequestDTO two
public class HelloH
{
public string Name1 { get; set; }
}
public class HelloResponse //ResponseDTO
{
public string Result { get; set; }
}
public class HelloServiceL : Service //Service One
{
public object Get(HelloL request)
{
return new HelloResponse { Result = "Low" };
}
}
public class HelloServiceH : Service //Service
{
public object Get(HelloH request)
{
return new HelloResponse { Result = "High" };
}
}
//Define the Web Services AppHost
public class AppHost : AppSelfHostBase
{
public AppHost()
: base("HttpListener Self-Host",new Assembly[] {typeof(HelloServiceL).Assembly, typeof(HelloServiceH).Assembly}) { }
public override void Configure(Funq.Container container) { }
}
//Run it!
static void Main(string[] args)
{
var listeningOn = args.Length == 0 ? "http://*:133/" : args[0];
var appHost = new AppHost()
.Init()
.Start(listeningOn);
Console.WriteLine("AppHost Created at {0}, listening on {1}",
DateTime.Now, listeningOn);
Console.ReadKey();
}
}
}
When I am tring to added two service then it is show below exception.
An unhandled exception of type 'System.Reflection.AmbiguousMatchException' occurred in ServiceStack.dll
Additional information: Could not register Request 'ManualCSharpe.MyServices+HelloL' with service 'ManualCSharpe.MyServices+HelloServiceL' as it has already been assigned to another service.
Each Request DTO can only be handled by 1 service.
I have below douts.
Here I have created two different DTO for Two Service. Why it is showing error like Each Request DTO can only be handled by 1 service. In simple word, Two route mapped with two DTO with two Service.
Can I create one route for multiple RequestDTO with multiple service? In Simple word, One Route/L/hello/ can be mapped with two DTO HelloL and HelloH.
You can't have Service class implementations nested inside another outer MyServices class:
public class MyServices : Service
{
[Route("/L/hello/")] //RequestDTO one
public class HelloL
{
public string Name { get; set; }
}
[Route("/H/hello/")] //RequestDTO two
public class HelloH
{
public string Name1 { get; set; }
}
public class HelloResponse //ResponseDTO
{
public string Result { get; set; }
}
public class HelloServiceL : Service //Service One
{
public object Get(HelloL request)
{
return new HelloResponse { Result = "Low" };
}
}
public class HelloServiceH : Service //Service
{
public object Get(HelloH request)
{
return new HelloResponse { Result = "High" };
}
}
}
Remove the outer MyServices class completely and just have the DTO's and Service classes directly under a C# namespace.
Also routes shouldn't end with a / suffix, so I'd change:
[Route("/L/hello/")]
to:
[Route("/L/hello")]
#mythz answer is correct for OP but I came here looking for an answer for a different situation which the cause was not particularly obvious - you will get this exception if you attempt to register the same assembly twice, for example, if you move a service implementation into the same assembly and were pulling it in like so:
public AppHost() : base("App", typeof(AdminService).GetAssembly(), typeof(InboundService).GetAssembly(),typeof(ProductService).GetAssembly())
For those of you who come here from a google search, a AmbiguousMatchException exception in ServiceStack can sometimes be triggered within ServiceStack but handled internally.
You can change your exception setting so it doesn't break on this exception.
I had changed my exception setting to break on all exceptions and this had me stuck for a while.

#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.

Can I change the default '/soap11' route for the SOAP endpoint on a ServiceStack implementation

I know I can manage the routes for the REST-ful interface operations by attributing the DTOs
[Route("/widgets", "GET, POST")]
[DataContract()]
public class GetWidgetsRequest
{
[DataMember]
public string OutletCode { get; set; }
[DataMember]
public IList<Specification> WidgetsCaptured { get; set; }
}
but I have searched and experimented unsuccessfully at trying to affect the default /soap11 appendage to the endpoint for a given SOAP operation.
**POST /soap11 HTTP/1.1**
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: nnn
SOAPAction: GetItemsRequest
A broader question within the question is, what are my options and how to configure the different endpoint settings?
Thanks!
Please read the SOAP Support docs for guidelines and limitations of using SOAP in ServiceStack.
For a different SOAP path, eg ~/services, you can add your own servicestack plugin , that returns your own servicestack soap handler.
public class MySoapFeature : IPlugin
{
private static IHttpHandler GetHandlerForPathParts(string[] pathParts)
{
string str2 = string.Intern(pathParts[0].ToLower());
if (pathParts.Length != 1) return null;
if (str2 == "services")
{
return new MySoapHttpHandler();
}
return null;
}
public IHttpHandler ProcessRequest(string httpMethod, string pathInfo, string filePath)
{
char[] chrArray = new char[] { '/' };
string[] strArrays = pathInfo.TrimStart(chrArray).Split(new char[] { '/' });
if ((int)strArrays.Length == 0)
{
return null;
}
return MySoapFeature.GetHandlerForPathParts(strArrays);
}
public void Register(IAppHost appHost)
{
appHost.CatchAllHandlers.Add(this.ProcessRequest);
}
}
Then implement this handler based on Soap11Handler or Soap12Handler
public class MySoapHttpHandler : Soap11Handler, IHttpHandler
{
public MySoapHttpHandler()
: base((EndpointAttributes)((long)32768))
{
}
public new void ProcessRequest(HttpContext context)
{
if (context.Request.HttpMethod == "GET")
{
(new Soap11WsdlMetadataHandler()).Execute(context);
return;
}
Message message = base.Send(null);
context.Response.ContentType = base.GetSoapContentType(context.Request.ContentType);
using (XmlWriter xmlWriter = XmlWriter.Create(context.Response.OutputStream))
{
message.WriteMessage(xmlWriter);
}
}
public override void ProcessRequest(IHttpRequest httpReq, IHttpResponse httpRes, string operationName)
{
if (httpReq.HttpMethod == "GET")
{
(new Soap11WsdlMetadataHandler()).Execute(httpReq, httpRes);
return;
}
Message message = base.Send(null, httpReq, httpRes);
httpRes.ContentType = base.GetSoapContentType(httpReq.ContentType);
using (XmlWriter xmlWriter = XmlWriter.Create(httpRes.OutputStream))
{
message.WriteMessage(xmlWriter);
}
}
Then register your plugin in the servicestack apphost Configure()
Plugins.Add(new MySoapFeature());
Then create your Dto classes for the request and response. Have "Response" added to the response dto class name. Do NOT put a Route attribute on the request Dto, as it gets routed by the Soap method name in the Xml.
[DataContract(Namespace = "http://mynamespace/schemas/blah/1.0")]
public class MySoapMethod
{}
DataContract(Namespace = "http://mynamespace/schemas/blah/1.0")]
public class MySoapMethodResponse
{
[DataMember]
public string SomeProperty { get; set; }
}
Then have a Service to implement the Soap Dto's
public class SOAPService : Service
{
public MySoapMethodResponse Post(MySoapMethod request)
{
var response = new MySoapMethodResponse();
response.SomeProperty = "blah";
return response;
}
}

Resources