Jenkins form validation with objects as parameters - jenkins

I'm building a plugin for Jenkins and I'm trying to validate my form (connection test method). This worked fine when all #QueryParameter were Strings.
Now I'm trying to send my form validation method an Object like this:
public FormValidation doTestConnection(
#QueryParameter("url") final String url,
#QueryParameter("timeout") final String timeout,
#QueryParameter("bypassProxy") final boolean bypassProxy,
#QueryParameter("deployerCredentialsConfig") final CredentialsConfig deployerCredentialsConfig,
#QueryParameter("resolverCredentialsConfig") final CredentialsConfig resolverCredentialsConfig
) throws ServletException {
In my global.jelly file I have this:
<f:validateButton
title="${%Test Connection}" progress="${%Testing...}"
method="testConnection"
with="url,timeout,bypassProxy,deployerCredentialsConfig,resolverCredentialsConfig"/>
My CredentialConfig class implements Serializable but I guess that is not enough becuase I'm getting this when clicking the "Test Connection" button:
java.lang.IllegalArgumentException: Failed to invoke public hudson.util.FormValidation
org.jfrog.hudson.MyBuilder$DescriptorImpl.doTestConnection(java.lang.String,java.lang.String,boolean,org.jfrog.hudson.CredentialsConfig,org.jfrog.hudson.CredentialsConfig) throws javax.servlet.ServletException
Jenkins has no good documentation for using objects inside of FormValidation calls.

Looking at the Jenkins documentation and the code behind <f:validateButton/>, I believe it's impossible have objects bind in validation logic.
The docs say (https://wiki.jenkins-ci.org/display/JENKINS/Jelly+form+controls):
The 'with' attribute specifies the input fields sent to the server for
the validation. They are matched against the field attribute or the
name attribute of other input controls. The values of the nearest
input fields above the are sent to the server, so
this means the button has to come after the input fields. Multiple
fields can be specified by using ','.
The code simply gets fields by the names - there is no "object assembly" (I believe it's only done during actual config submission).
https://github.com/jenkinsci/jenkins/blob/96ec7a267e0efba2ec99590c871db0940e35920f/war/src/main/webapp/scripts/hudson-behavior.js#L2856

I bumped into a similar problem. Looking at the code, it seems stapler tries to convert your parameter to the type you provided in the doCheck function declaration.
class HandlerImpl extends AnnotationHandler<QueryParameter> {
public Object parse(StaplerRequest request, QueryParameter a, Class type, String parameterName) throws ServletException {
String name = a.value();
if(name.length()==0) name=parameterName;
if(name==null)
throw new IllegalArgumentException("Parameter name unavailable neither in the code nor in annotation");
String value = request.getParameter(name);
if(a.required() && value==null)
throw new ServletException("Required Query parameter "+name+" is missing");
if(a.fixEmpty() && value!=null && value.length()==0)
value = null;
return convert(type,value); // <--- HERE
}
}
As a workaround, I changed the type to boolean, like so:
public FormValidation doTestConnection(
#QueryParameter("url") final String url,
#QueryParameter("timeout") final String timeout,
#QueryParameter("bypassProxy") final boolean bypassProxy,
#QueryParameter("deployerCredentialsConfig") final boolean deployerCredentialsConfig,
#QueryParameter("resolverCredentialsConfig") final boolean resolverCredentialsConfig
) throws ServletException {
This allows me to at least check if the variable is set. It might not be enough for your use case, though.

Related

Update final fields only if not null in constructor dart

I have a class called App with some fields.
I want to initalize the final fields only if passed parameters to constructor are not null.
e.g in below code I want to set config param only if it is not null.
I tried below code but it is not working
#immutable
class App {
final AuthState auth;
final RConfig config;
App({AuthState auth, this.config}):
auth = auth ?? new AuthState(), config = config != null ? config : this.config ;
Although I am quite new to dart, I know that I can't initalize final fields twice but there are app states due to which AppState get created again and RConfig may be null at that time.
My question is as simple is this how to check multiple final fields validity e.g null or empty before assigning them.
You cannot initialize a field twice. You initialize config both with an initializing formal (this.config) and an initializer list entry config = ....
I'm not sure what you are trying to do with config, but start by declaring it as a normal parameter, then figure out what you want to do:
AppState({AuthState auth, RConfig config})
: auth = auth ?? new AuthState(), config = config; // or something

DartPad keeps saying expecting 2, receiving 3 arguments in constructor

Email( List<String> to, String from, {String subject:null, String message:null, DateTime datetime:null, HashMap<String, List<String>> meta:null, List<Attachment> attachments:null})
get this error:
Uncaught NoSuchMethodError: incorrect number of arguments passed to method named ''
Receiver: ""
Tried calling: (Instance of 'JSArray<String>', "will#fallenreaper.com", Instance of '_HashMap<String, Object>')
Found: (to, from, subject, message, datetime, meta, attachments)
My class is:
class Email{
Email( List<String> to, String from, {String subject:null, String message:null, DateTime datetime:null, HashMap<String, List<String>> meta:null, List<Attachment> attachments:null}){
//do stuff.
}
}
im trying to make it such that to and from are required, but the rest are optionally going to be passed in, in a map. I thought i was doing this right, but it doesnt seem to be correct.
The DartPad is at: https://dartpad.dartlang.org/4d32b88095a6509da511
Search for TODO
The Composer class is the part im implementing, leveraging the Email class i created.
Add some text to the Subject, and then click the "Send" button
Your Email class' constructor
Email( List<String> to, String from, {String subject:null, String message:null, DateTime datetime:null, HashMap<String, List<String>> meta:null, List<Attachment> attachments:null}) { ... }
has 2 positional arguments and 5 optional named arguments.
You can simply pass positional parameters like you did in
new Email(map["to"], map["from"], map);
but optional names parameters need to be "named" like
new Email(map["to"], map["from"], subject: map);
If you want the optional parameters to be positional you need to change the constructor to
Email( List<String> to, String from, [String subject=null, String message=null, DateTime datetime=null, HashMap<String, List<String>> meta=null, List<Attachment> attachments=null]) { ... }
You can't have optional named and optional positional arguments at the same time. If you have a longer parameter list like in your Email constructor, named optional arguments are usually better because you can specify with a name which parameter the passed value should be assigned to and there is no need to pass nulls or ''s for parameters you want to skip.

Upgrading to MVC4 RC: No MediaTypeFormatter is available to read an object of type 'TestRequestModel' from content with media type ''undefined''

I've been using the MVC4 beta and am currently working to upgrade to the recently released RC version.
It appears that model-binding complex request types has changed, but I can't figure out how / what I'm doing wrong.
For example, say I have the following API controller:
public class HomeApiController : ApiController
{
public TestModel Get()
{
return new TestModel
{
Id = int.MaxValue,
Description = "TestDescription",
Time = DateTime.Now
};
}
}
This yields the expected result:
<TestModel xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/xxxx">
<Description>TestDescription</Description>
<Id>2147483647</Id>
<Time>2012-06-07T10:30:01.459147-04:00</Time>
</TestModel>
Now say I just change the signature, taking in a request type, like this:
public TestModel Get(TestRequestModel request)
{
...
public class TestRequestModel
{
public int? SomeParameter { get; set; }
}
I now get the following error:
<Exception xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/System.Web.Http.Dispatcher">
<ExceptionType>System.InvalidOperationException</ExceptionType>
<Message>
No MediaTypeFormatter is available to read an object of type 'TestRequestModel' from content with media type ''undefined''.
</Message>
<StackTrace>
at System.Net.Http.HttpContentExtensions.ReadAsAsync[T](HttpContent content, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger) at System.Net.Http.HttpContentExtensions.ReadAsAsync(HttpContent content, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger) at System.Web.Http.ModelBinding.FormatterParameterBinding.ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken) at System.Web.Http.Controllers.HttpActionBinding.<>c__DisplayClass1.<ExecuteBindingAsync>b__0(HttpParameterBinding parameterBinder) at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext() at System.Threading.Tasks.TaskHelpers.IterateImpl(IEnumerator`1 enumerator, CancellationToken cancellationToken)
</StackTrace>
</Exception>
I've looked at the source code of where this exception is thrown in the HttpContentExtensions, but it looks like it checks for content headers (which I should have), and if it doesn't have that it tries to get a formatter from the MediaTypeFormatter collection it has for the specific type (which it can't) and then throws.
Anyone else experienced this? Some global registration I'm missing?
I see your original question was answered, but to answer the other one, Model binding has changed somewhat in the RC.
http://weblogs.thinktecture.com/cweyer/2012/06/aspnet-web-api-changes-from-beta-to-rc.html
This link has some details about it. But to sum up the change that appears to be affecting you, Model binding pulls its values from either the body, or the uri of the request. This is true for previous releases as well, but with the release candidate, MVC4 will, by default, look to the body for complex types, and the uri for value types.
So, if you submit a body with your request containing the "SomeParameter" key, you should see it bind. Or you could bind with the url if you change the declaration to:
public TestModel Get(int? someParameter)
{
}
Thankfully, the team foresaw the potential problems with this and left us with attributes we could use to override this behavior.
public TestModel Get([FromUri]TestRequestModel request)
{
}
The key here is the [FromUri] which tells the model binder to look in the uri for the values. There is also [FromBody] if you want to put a value type in the body of a request.
We were seeing the same thing. In our case the problem was a complex object being passed into a get method. We needed to add a [FromUri] attribute in the parameter to that method.
http://forums.asp.net/t/1809925.aspx/1?GET+requests+with+complex+object+as+input+parameter
public class SearchController : ApiController
{
// added [FromUri] in beta to RC transition otherwise media type formatter error
public IQueryable<SearchResultEventModel> Get( [FromUri]SearchSpecModel search )
{
// ...
}
}

Pass dynamic parameters in the keyvalue (message key) to package.properties

I have tried to pass dynamic parameters to keyvalue(message to display) which I will get from package.properties to the Action class through the getText() method. To get the message, we can use getText(String keyvalue) method. What should I do to pass some parameters and retrieve the parameters with the message through the getText() method?
I saw some API's to pass dynamic parameters. But I don't know how to use, these are the following API's, click here to see the Struts 2 API Documentation.
getText(String aTextName, List<Object> args)
getText(String key, String[] args)
getText(String key, String defaultValue, String[] args)
Thanks in advance..
I suppose that you have following properties in your package.properties
username.required=user name is required
password.required=password is required
you can use getText() as
getText("username.required")
getText("password.required")
Now if we want to use getText(String key, String[] args) we have to pass following parameters
aTextName - the resource bundle key that is to be searched for
args - a list args to be used in a MessageFormat message
That means the message format pattern and other static strings will, of course, be obtained from resource bundles. Other parameters will be dynamically determined at runtime.
example
we have following entry in resource file
disk.data=The disk \"{0}\" artist name is {1}.
in this {1} and {0} are the dynamic parameters and will be determined at run time so args will contain the value of these parameters.
String artistName= demo;
String diskName = "Artist";
String[] testArgs = {artistName, diskName};
So final call will be getText(disk.data, testArgs);
and it will show
The disk demo artist name is Artist.
Please go through MessageFormat to know how this work

symfony 1.4 using post validator in New action throws error

I have the following action for a form. In the MyForm definition, I added post validator, so I can validate two fields at a time by certain condition. The problem comes when, after passing validation, symfony sends me an error, and also stores null values in a new record in the database. I post my code here... My form just has two fields, and the user most select each of them from two lists to create a new record. By schema restrictions, the combination of both fields is unique. Also, I need to validate that certain combinations of this fields aren't allowed for the creation of a new record.
actions.class.php:
public function executeNew(sfWebRequest $request)
{
$this->form = new MyForm();
}
public function executeCreate(sfWebRequest $request)
{
$this->forward404Unless($request->isMethod(sfRequest::POST));
$this->form = new MyForm();
$this->processForm($request, $this->form, true);
$this->setTemplate('new');
}
protected function processForm(sfWebRequest $request, sfForm $form, $new = false)
{
$form->bind($request->getParameter($form->getName()),
$request->getFiles($form->getName()));
if ($form->isValid())
{
$post = $form->save();
$this->redirect('post/' . $post->getId());
}
}
MyForm.class.php
class MyForm extends BaseMyForm
{
public function configure()
{
$this->widgetSchema['field1'] = new sfWidgetFormChoice(array('choices' => MyUtil::$field1_vaues));
$this->widgetSchema['field2'] = new sfWidgetFormChoice(array('choices' => MyUtil::$field2_values));
$this->mergePostValidator(new sfValidatorCallback(array('callback' => array($this, 'validateBothFields'))));
}
public function validateBothFields($validator, $values, $arguments)
{
if (MyUtil::fields_relation($values['field1'], $values['field2']))
{
throw new sfValidatorError($validator, "Fields relation invalid!");
}
}
}
When I comment out the mergePostValidator line, then all works fine, but then I cannot validate the condition of not accepting certain combination of my two fields.
And when using this code as is: if the combination is invalid, all works well, the form appears again with the 'Fields relation invalid!' message. But if the combination is valid, symfony throws the following errors:
Warning: Invalid argument supplied for foreach() in /path/to/symfony/lib/plugins/sfDoctrinePlugin/lib/form/sfFormDoctrine.class.php on line 169
Catchable fatal error: *Argument 1 passed to Doctrine_Record::fromArray() must be an array, null given, called in /path/to/symfony/lib/plugins/sfDoctrinePlugin/lib/form/sfFormDoctrine.class.php on line 150 and defined in /แน•ath/to/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Record.php on line 1970*
Warning: Invalid argument supplied for foreach() in /path/to/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Record.php on line 1973
and then some warnings/errors about not being able to modify headers to response (but I am not modifying any by myself, and perhaps is just the $this->setTemplate('new') in the action Create method...
I'm using Symfony 1.4.9, but also tried with the 1.4 development branch from the SVN server (rev 32070) and got the same result.
Apache 2.2, PHP 5.2.6
A validator needs to return the cleaned value - same for the post validator. Add a return $values; to the end of your function.
Your problem comes from missing this, therefore later a null is passed to a foreach() call, causing your first error. Same reason for the others.
Null values are stored because you effectively zero out every value passed to the form by missing this return.

Resources