Populating Action class instance variables from URL in Struts2 - java

Facing an issue with passing values from my html form to action class. Created a sample project to test the functionality and have the same issue here. I have the following classes:
TestBean
package com.struts2test.beans;
public class TestBean {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
TestBeanHolder
package com.struts2test.beans;
import java.util.List;
import java.util.Map;
public class TestBeanHolder {
private Map<Integer, TestBean> testBeanMap;
private List<TestBean> testBeanList;
private Map<Integer, List<TestBean>> testBeanListMap;
public Map<Integer, TestBean> getTestBeanMap() {
return testBeanMap;
}
public void setTestBeanMap(Map<Integer, TestBean> testBeanMap) {
this.testBeanMap = testBeanMap;
}
public Map<Integer, List<TestBean>> getTestBeanListMap() {
return testBeanListMap;
}
public void setTestBeanListMap(Map<Integer, List<TestBean>> testBeanListMap) {
this.testBeanListMap = testBeanListMap;
}
public List<TestBean> getTestBeanList() {
return testBeanList;
}
public void setTestBeanList(List<TestBean> testBeanList) {
this.testBeanList = testBeanList;
}
}
TestAction
package com.struts2test.action;
import com.opensymphony.xwork2.ActionSupport;
import com.struts2test.beans.TestBeanHolder;
public class TestAction extends ActionSupport {
private static final long serialVersionUID = 1L;
private TestBeanHolder testBeanHolder;
public TestBeanHolder getTestBeanHolder() {
return testBeanHolder;
}
public void setTestBeanHolder(TestBeanHolder testBeanHolder) {
this.testBeanHolder = testBeanHolder;
}
public String execute() throws Exception {
return SUCCESS;
}
}
When my url is http://localhost:8080/Struts2Test/test?testBeanHolder.testBeanMap[0].value=1, testBeanHolder.testBeanMap of my action gets populated with key of 0 mapping to a TestBean instance with value=1.
When the url is http://localhost:8080/Struts2Test/test?testBeanHolder.testBeanList[0].value=1, testBeanHolder.testBeanList gets populated with single instance of TestBean with value=1.
I am try to populate testBeanListMap property of testBeanHolder and doesn't work. The testBeanListMap is created but empty. Here is the URL I am trying http://localhost:8080/Struts2Test/test?testBeanHolder.testBeanListMap[0][0].value=1

Here is the code which worked, adding modified classes:
TestBeanListHolder
package com.struts2test.beans;
import java.util.List;
public class TestBeanListHolder {
private List<TestBean> testBeans;
public List<TestBean> getTestBeans() {
return testBeans;
}
public void setTestBeans(List<TestBean> testBeans) {
this.testBeans = testBeans;
}
}
TestBeanHolder
package com.struts2test.beans;
import java.util.List;
import java.util.Map;
public class TestBeanHolder {
private Map<Integer, TestBean> testBeanMap;
private List<TestBean> testBeanList;
private Map<Integer, TestBeanListHolder> testBeanListMap;
public Map<Integer, TestBean> getTestBeanMap() {
return testBeanMap;
}
public void setTestBeanMap(Map<Integer, TestBean> testBeanMap) {
this.testBeanMap = testBeanMap;
}
public Map<Integer, TestBeanListHolder> getTestBeanListMap() {
return testBeanListMap;
}
public void setTestBeanListMap(
Map<Integer, TestBeanListHolder> testBeanListMap) {
this.testBeanListMap = testBeanListMap;
}
public List<TestBean> getTestBeanList() {
return testBeanList;
}
public void setTestBeanList(List<TestBean> testBeanList) {
this.testBeanList = testBeanList;
}
}
URL
http://localhost:8080/Struts2Test/test?testBeanHolder.testBeanListMap[1].testBeans[0].value=somevalue

The url http://localhost:8080/Struts2Test/test?testBeanHolder.testBeanListMap[0][0].value=1 won't work because you are using wrong parameter name. Thus testBeanHolder.testBeanListMap[0][0].value is a name of the parameter that maps to the object which has a property of complex type (collection of collections). Struts2 can't handle such scenarios, . But you can wrap a second collection with an object and use a collection of objects. The name would change to testBeanHolder.testBeanListMap[0].object[0].value.

The expression testBeanHolder.testBeanListMap[0][0].value is not a valid OGNL expression.
See here for a complete reference of what is allowed.

Related

Limit instance construction to an external factory

The pattern I'm aiming for is to put all the classes that I want clients to use - like model objects, interfaces and factories - in a "client" package and put the private implementation in an impl package that is inaccessible to clients.
I only want clients to access my API using interfaces and I want to prevent them from instantiating private implementation classes directly.
What follows is a simple example. It works but am wondering if there's a better way - I'd imagine that this is a commonly used pattern?
package client;
public interface Plant {
String getScientificName();
String getCommonName();
}
package client;
import impl.PlantImpl;
import java.util.function.BiFunction;
public final class PlantFactory {
private BiFunction<String, String, Plant> delegate;
public PlantFactory() {
PlantImpl.registerFactory(this);
}
public void setFactory(BiFunction<String, String, Plant> factory) {
delegate = factory;
}
public Plant newInstance(String scientificName, String commonName) {
return delegate.apply(scientificName, commonName);
}
}
package impl;
import client.Plant;
import client.PlantFactory;
import java.util.function.BiFunction;
public final class PlantImpl implements Plant {
private final String scientificName;
private final String commonName;
private PlantImpl(String scientificName, String commonName) {
this.scientificName = scientificName;
this.commonName = commonName;
}
#Override
public String getScientificName() {
return scientificName;
}
#Override
public String getCommonName() {
return commonName;
}
public static void registerFactory(PlantFactory plantFactory) {
plantFactory.setFactory(new Factory());
}
static class Factory implements BiFunction<String, String, Plant> {
#Override
public Plant apply(String scientificName, String commonName) {
return new PlantImpl(scientificName, commonName);
}
}
}
import client.Plant;
import client.PlantFactory;
public final class PlantViewer {
public static void main(String[] args) {
// Doesn't compile due to private constructor
// Plant wattle = new PlantImpl("Acacia longifolia", "Sydney Golden Wattle");
PlantFactory plantFactory = new PlantFactory();
Plant grevillea = plantFactory.newInstance("Grevillea caleyi", "Caley's Grevillea");
System.out.println("Plant name is " + grevillea.getCommonName());
}
}

how to implement public AbstractEntryProcessor(boolean applyOnBackup){} in 5.x.x for the backup in Hazelcast

Help me in the following code and how to used the backup on the Hazelcast
migration of the hazelcast 3.x.x to 5.x.x
package com.hazelcast.map;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.HazelcastInstanceAware;
import com.hazelcast.nio.serialization.impl.BinaryInterface;
import java.util.Map;
// Interface AbstractEntryProcessor
#BinaryInterface
public abstract class AbstractEntryProcessor<K,V> implements EntryProcessor<K,V> {
private final EntryBackupProcessor<K,V> entryBackupProcessor;
// Non Parameterize Constructor
public AbstractEntryProcessor() {
this(true);
}
// Parameterize Constructor AbstractEntryProcessor
public AbstractEntryProcessor(boolean applyOnBackup) {
if (applyOnBackup) {
entryBackupProcessor = new EntryBackupProcessorImpl();
} else {
entryBackupProcessor = null;
}
}
//EntryBackupProcessor
#Override
public final EntryBackupProcessor getBackupProcessor() {
return entryBackupProcessor;
}
// class EntryBackupProcessorImpl
private class EntryBackupProcessorImpl implements EntryBackupProcessor<k,V>, HazelcastInstanceAware {
// generated for EntryBackupProcessorImpl which doesn't implement HazelcastInstanceAware
static final long serialVersionUID = -5081502753526394129L;
#Override
public void processBackup(Map.Entry<K,V> entry) {
process(entry);
}
#Override
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
final AbstractEntryProcessor<k,V> outer = AbstractEntryProcessor.this;
if (outer instanceof HazelcastInstanceAware) {
((HazelcastInstanceAware) outer).setHazelcastInstance(hazelcastInstance);
}
}
}
}
How to used the backup methods in 5.x.x versons of series
how to used the backup in the above question ?
This should work:
public abstract class AbstractEntryProcessor implements EntryProcessor, HazelcastInstanceAware {
protected transient HazelcastInstance hazelcastInstance;
private final boolean applyOnBackup;
// Non Parameterize Constructor
public AbstractEntryProcessor() {
this(true);
}
// Parameterize Constructor AbstractEntryProcessor
public AbstractEntryProcessor(boolean applyOnBackup) {
this.applyOnBackup = applyOnBackup;
}
//EntryBackupProcessor
#Override
public final EntryProcessor getBackupProcessor() {
if (!applyOnBackup || this instanceof ReadOnly) {
return null;
}
return this;
}
#Override
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
this.hazelcastInstance = hazelcastInstance;
}
}

XStream implicit configouration

I am working with XML like:
<localMSZ>
<territories>
<codeOKTMO>str1</codeOKTMO>
<codeOKTMO>str2</codeOKTMO>
</territories>
</localMSZ>
In Java code I have class LocalMSZ which have List of String like:
class LocalMSZ {
List<String> territories;
}
I doesn't understand how I should post annotation in this case?
The problem is in your mapping class: it lacks the structure and annotations needed for this. It should work with this:
import java.util.LinkedList;
import java.util.List;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamConverter;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import com.thoughtworks.xstream.converters.extended.ToAttributedValueConverter;
#XStreamAlias("localMSZ")
public class LocalMSZ {
private Territories territories = new Territories();
public Territories getTerritories() {
return territories;
}
public void setTerritories(Territories territories) {
this.territories = territories;
}
#XStreamAlias("codeOKTMO")
#XStreamConverter(value = ToAttributedValueConverter.class, strings = { "value" })
public static class Code {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
#XStreamAlias("territories")
public static class Territories {
// This one maps the sequence of <codeOKTMO> tags
#XStreamImplicit
private List<Code> codes = new LinkedList<Code>();
public List<Code> getCodes() {
return codes;
}
public void setCodes(List<Code> codes) {
this.codes = codes;
}
}
}
Remember also when you write your main method to process the annotations of LocalMSZ
XStream xstream = new XStream();
xstream.processAnnotations(LocalMSZ.class);
...

MusixMatch API and GSON: Using track.snippet.get instead of track.lyrics.get

I am working on the final project for an intro to Java class. Part of the project involves getting a lyric snippet from MusixMatch using their API. I am able to get lyrics from the API using track.lyrics.get, but cannot get snippets using tracks.snippet.get.
I started with a Java wrapper found here: https://github.com/sachin-handiekar/jMusixMatch and added my own classes to get a snippet based on the track.snippet.get API method.
When I run the program I get this error:
java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at
line 1 column 102 path $.message.body
My getSnippet method and applicable classes follow. They are based on the getLyrics method and classes found in the original wrapper.
public Snippet getSnippet(int trackID) throws MusixMatchException {
Snippet snippet = null;
SnippetGetMessage message = null;
Map<String, Object> params = new HashMap<String, Object>();
params.put(Constants.API_KEY, apiKey);
params.put(Constants.TRACK_ID, new String("" + trackID));
String response = null;
response = MusixMatchRequest.sendRequest(Helper.getURLString(
Methods.TRACK_SNIPPET_GET, params));
Gson gson = new Gson();
try {
message = gson.fromJson(response, SnippetGetMessage.class);
} catch (JsonParseException jpe) {
handleErrorResponse(response);
}
snippet = message.getContainer().getBody().getSnippet();
return snippet;
}
The Snippet Class
package org.jmusixmatch.entity.snippet;
import com.google.gson.annotations.SerializedName;
/**
* Created by kyledhebert on 4/30/15.
* Objects of this clas represent a lyric snippet from the
* MusixMatch API.
*/
public class Snippet {
#SerializedName("snippet_language")
private int snippetLanguage;
#SerializedName("restricted")
private int restricted;
#SerializedName("instrumental")
private int instrumental;
#SerializedName("snippet_body")
private String snippetBody;
#SerializedName("script_tracking_url")
private String scriptTrackingURL;
#SerializedName("pixel_tracking_url")
private String pixelTrackingURL;
#SerializedName("html_tracking_url")
private String htmlTrackingURL;
#SerializedName("updated_time")
private String updatedTime;
public int getSnippetLanguage() {
return snippetLanguage;
}
public void setSnippetLanguage(int snippetLanguage) {
this.snippetLanguage = snippetLanguage;
}
public int getRestricted() {
return restricted;
}
public void setRestricted(int restricted) {
this.restricted = restricted;
}
public int getInstrumental() {
return instrumental;
}
public void setInstrumental(int instrumental) {
this.instrumental = instrumental;
}
public String getSnippetBody() {
return snippetBody;
}
public void setSnippetBody(String snippetBody) {
this.snippetBody = snippetBody;
}
public String getPixelTrackingURL() {
return pixelTrackingURL;
}
public void setPixelTrackingURL(String pixelTrackingURL) {
this.pixelTrackingURL = pixelTrackingURL;
}
public String getScriptTrackingURL() {
return scriptTrackingURL;
}
public void setScriptTrackingURL(String scriptTrackingURL) {
this.scriptTrackingURL = scriptTrackingURL;
}
public String getHtmlTrackingURL() {
return htmlTrackingURL;
}
public void setHtmlTrackingURL(String htmlTrackingURL) {
this.htmlTrackingURL = htmlTrackingURL;
}
public String getUpdatedTime() {
return updatedTime;
}
public void setUpdatedTime(String updatedTime) {
this.updatedTime = updatedTime;
}
}
The SnippetGetBody class:
package org.jmusixmatch.entity.snippet.get;
import com.google.gson.annotations.SerializedName;
import org.jmusixmatch.entity.snippet.Snippet;
public class SnippetGetBody {
#SerializedName("snippet")
private Snippet snippet;
public Snippet getSnippet() {
return snippet;
}
public void setSnippet(Snippet snippet) {
this.snippet = snippet;
}
}
The SnippetGetContainer class:
package org.jmusixmatch.entity.snippet.get;
import com.google.gson.annotations.SerializedName;
import org.jmusixmatch.entity.Header;
public class SnippetGetContainer {
#SerializedName("body")
private SnippetGetBody body;
#SerializedName("header")
private Header header;
public SnippetGetBody getBody() {
return body;
}
public void setBody(SnippetGetBody body) {
this.body = body;
}
public Header getHeader() {
return header;
}
public void setHeader(Header header) {
this.header = header;
}
}
The SnippetGetMessage class:
package org.jmusixmatch.entity.lyrics.get;
import com.google.gson.annotations.SerializedName;
public class SnippetGetMessage {
#SerializedName("message")
private SnippetGetContainer container;
public void setContainer(SnippetGetContainer container) {
this.container = container;
}
public SnippetGetContainer getContainer() {
return container;
}
}
I was not able to reproduce your exact error message, but I did find the following error: snippet_language is a String, not an int. Change the type (and associated getters and setters) to:
#SerializedName("snippet_language")
private String snippetLanguage;
I used the sample Json response from here to make this work. If these two changes don't fix your problem, please edit your question with the actual Json response that is making your program not work.

Instantiating/Referencing static nested class inside static nested class

I have been give a jar file to use that has a static inner class inside of another static inner class:
package externalJarFile;
public class Job
{
public static class GlobalVars
{
private List<Job.GlobalVars.Variable> variables;
public List<Job.GlobalVars.Variable> getVariable()
{
if (this.variables == null) {
this.variables = new ArrayList<Job.GlobalVars.Variable>();
}
return this.variables;
}
public static class Variable
{
String name;
String value;
public String getName() { return name; }
public void setName( String name ) { this.name = name; }
public String getValue() { return value; }
public void setValue( String value) { this.value= value; }
}
}
}
The problem I'm having is that I need to populate the "Job.GlobalVars" list, but I can't figure out how to reference the "Variables" type. Whenever I add:
import externalJarFile.Job.GlobalVars.Variable;
I get a compilation error that the type "externalJarFile.Job.GlobalVars.Variable" cannot be referenced. How can I create a new "Variable" instance to add to the "GlobalVars.getVariable()" list?
Here's a snippet that I tried (but didn't work):
Job.GlobalVars vars = new Job.GlobalVars();
Job.GlobalVars.Variable v = new Job.GlobalVars.Variable();
[Edited for clarity]
[UPDATE]
Ok, this is kinda weird. If I take the code from the original project and directly import it into mine, I'm able to reference the inner-inner-class. However, when I reference it when it's packaged inside of a jar file, it fails. MTK...
You forgot a space:
Job.GlobalVars vars = new Job.GlobalVars();
^
This works fine for me:
Job.GlobalVars.Variable var = new Job.GlobalVars.Variable();
var.setName("MByD");
Class job:
package mypackage;
import java.util.ArrayList;
import java.util.List;
public class Job {
public static class GlobalVars
{
private List<Variable> variables;
public List<Variable> getVariable()
{
if (this.variables == null) {
this.variables = new ArrayList<Variable>();
}
return this.variables;
}
public static class Variable
{
String name;
String value;
public String getName() { return name; }
public void setName( String name ) { this.name = name; }
public String getValue() { return value; }
public void setValue( String value) { this.value= value; }
}
}
}
Other class using GlobalVars and Variable. Import works very good.
package mypackage;
import mypackage.Job.GlobalVars;
import mypackage.Job.GlobalVars.Variable;
public class RunIt {
public static void main(String[] args) {
GlobalVars vars = new GlobalVars();
Variable v = new Variable();
}
}
No need to import anything. You should be able to just refer to your inner class by its name, "Variable", from the "Job" class:
private List<Variable> variables;
public List<Variable> getVariable()
They way you had stated above is correct. You should check to ensure that the jar file is in your classpath as that would definitely cause the import to fail and subsequently all future declarations.
import mypackage.Job.GlobalVars.Variable;
...
Variable v = new Variable();

Categories

Resources